mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
core: turn a memblock in the parser to std::string
This avoid memory-management troubles. Had to convert a few of the parsers (cochran, datatrak, liquivision) to C++. Also had to convert libdivecomputer.c. This was less painful than expected. std::string is used because parts of the code assumes that the data is null terminated after the last character of the data. std::string does precisely that. One disadvantage is that std::string clears its memory when resizing / initializing. Thus we read the file onto freshly cleared data, which some might thing is a performance regression. Until someone shows me that this matters, I don't care. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
2f4dbf1848
commit
cf7c54bd56
12 changed files with 233 additions and 285 deletions
|
@ -60,7 +60,7 @@ SOURCES += subsurface-mobile-main.cpp \
|
||||||
core/gaspressures.c \
|
core/gaspressures.c \
|
||||||
core/git-access.cpp \
|
core/git-access.cpp \
|
||||||
core/globals.cpp \
|
core/globals.cpp \
|
||||||
core/liquivision.c \
|
core/liquivision.cpp \
|
||||||
core/load-git.cpp \
|
core/load-git.cpp \
|
||||||
core/parse-xml.cpp \
|
core/parse-xml.cpp \
|
||||||
core/parse.cpp \
|
core/parse.cpp \
|
||||||
|
@ -76,14 +76,14 @@ SOURCES += subsurface-mobile-main.cpp \
|
||||||
core/save-html.c \
|
core/save-html.c \
|
||||||
core/statistics.c \
|
core/statistics.c \
|
||||||
core/worldmap-save.c \
|
core/worldmap-save.c \
|
||||||
core/libdivecomputer.c \
|
core/libdivecomputer.cpp \
|
||||||
core/version.c \
|
core/version.c \
|
||||||
core/save-git.cpp \
|
core/save-git.cpp \
|
||||||
core/datatrak.c \
|
core/datatrak.cpp \
|
||||||
core/ostctools.c \
|
core/ostctools.c \
|
||||||
core/planner.c \
|
core/planner.c \
|
||||||
core/save-xml.cpp \
|
core/save-xml.cpp \
|
||||||
core/cochran.c \
|
core/cochran.cpp \
|
||||||
core/deco.c \
|
core/deco.c \
|
||||||
core/divesite.c \
|
core/divesite.c \
|
||||||
core/equipment.c \
|
core/equipment.c \
|
||||||
|
|
|
@ -41,7 +41,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||||
checkcloudconnection.h
|
checkcloudconnection.h
|
||||||
cloudstorage.cpp
|
cloudstorage.cpp
|
||||||
cloudstorage.h
|
cloudstorage.h
|
||||||
cochran.c
|
cochran.cpp
|
||||||
cochran.h
|
cochran.h
|
||||||
color.cpp
|
color.cpp
|
||||||
color.h
|
color.h
|
||||||
|
@ -51,7 +51,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||||
configuredivecomputerthreads.h
|
configuredivecomputerthreads.h
|
||||||
connectionlistmodel.cpp
|
connectionlistmodel.cpp
|
||||||
connectionlistmodel.h
|
connectionlistmodel.h
|
||||||
datatrak.c
|
datatrak.cpp
|
||||||
datatrak.h
|
datatrak.h
|
||||||
deco.c
|
deco.c
|
||||||
deco.h
|
deco.h
|
||||||
|
@ -121,9 +121,9 @@ set(SUBSURFACE_CORE_LIB_SRCS
|
||||||
import-suunto.cpp
|
import-suunto.cpp
|
||||||
import-seac.cpp
|
import-seac.cpp
|
||||||
interpolate.h
|
interpolate.h
|
||||||
libdivecomputer.c
|
libdivecomputer.cpp
|
||||||
libdivecomputer.h
|
libdivecomputer.h
|
||||||
liquivision.c
|
liquivision.cpp
|
||||||
load-git.cpp
|
load-git.cpp
|
||||||
membuffer.cpp
|
membuffer.cpp
|
||||||
membuffer.h
|
membuffer.h
|
||||||
|
|
|
@ -207,7 +207,7 @@ static void cochran_debug_sample(const char *s, unsigned int sample_cnt)
|
||||||
static void cochran_parse_header(const unsigned char *decode, unsigned mod,
|
static void cochran_parse_header(const unsigned char *decode, unsigned mod,
|
||||||
const unsigned char *in, unsigned size)
|
const unsigned char *in, unsigned size)
|
||||||
{
|
{
|
||||||
unsigned char *buf = malloc(size);
|
unsigned char *buf = (unsigned char *)malloc(size);
|
||||||
|
|
||||||
/* Do the "null decode" using a one-byte decode array of '\0' */
|
/* Do the "null decode" using a one-byte decode array of '\0' */
|
||||||
/* Copies in plaintext, will be overwritten later */
|
/* Copies in plaintext, will be overwritten later */
|
||||||
|
@ -441,7 +441,7 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||||
const unsigned char *s;
|
const unsigned char *s;
|
||||||
unsigned int offset = 0, profile_period = 1, sample_cnt = 0;
|
unsigned int offset = 0, profile_period = 1, sample_cnt = 0;
|
||||||
double depth = 0, temp = 0, depth_sample = 0, psi = 0, sgc_rate = 0;
|
double depth = 0, temp = 0, depth_sample = 0, psi = 0, sgc_rate = 0;
|
||||||
int ascent_rate = 0;
|
//int ascent_rate = 0;
|
||||||
unsigned int ndl = 0;
|
unsigned int ndl = 0;
|
||||||
unsigned int in_deco = 0, deco_ceiling = 0, deco_time = 0;
|
unsigned int in_deco = 0, deco_ceiling = 0, deco_time = 0;
|
||||||
|
|
||||||
|
@ -517,8 +517,8 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||||
switch (config.type) {
|
switch (config.type) {
|
||||||
case TYPE_COMMANDER:
|
case TYPE_COMMANDER:
|
||||||
switch (sample_cnt % 2) {
|
switch (sample_cnt % 2) {
|
||||||
case 0: // Ascent rate
|
case 0: // Ascent rate (unused)
|
||||||
ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1);
|
//ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1);
|
||||||
break;
|
break;
|
||||||
case 1: // Temperature
|
case 1: // Temperature
|
||||||
temp = s[1] / 2 + 20;
|
temp = s[1] / 2 + 20;
|
||||||
|
@ -528,8 +528,8 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||||
case TYPE_GEMINI:
|
case TYPE_GEMINI:
|
||||||
// Gemini with tank pressure and SAC rate.
|
// Gemini with tank pressure and SAC rate.
|
||||||
switch (sample_cnt % 4) {
|
switch (sample_cnt % 4) {
|
||||||
case 0: // Ascent rate
|
case 0: // Ascent rate (unused)
|
||||||
ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1);
|
//ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1);
|
||||||
break;
|
break;
|
||||||
case 2: // PSI change
|
case 2: // PSI change
|
||||||
psi -= (double)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4;
|
psi -= (double)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4;
|
||||||
|
@ -544,8 +544,8 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||||
break;
|
break;
|
||||||
case TYPE_EMC:
|
case TYPE_EMC:
|
||||||
switch (sample_cnt % 2) {
|
switch (sample_cnt % 2) {
|
||||||
case 0: // Ascent rate
|
case 0: // Ascent rate (unused)
|
||||||
ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1);
|
//ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1);
|
||||||
break;
|
break;
|
||||||
case 1: // Temperature
|
case 1: // Temperature
|
||||||
temp = (double)s[1] / 2 + 20;
|
temp = (double)s[1] / 2 + 20;
|
||||||
|
@ -597,7 +597,6 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
|
||||||
offset += config.sample_size;
|
offset += config.sample_size;
|
||||||
sample_cnt++;
|
sample_cnt++;
|
||||||
}
|
}
|
||||||
UNUSED(ascent_rate); // mark the variable as unused
|
|
||||||
|
|
||||||
if (sample_cnt > 0)
|
if (sample_cnt > 0)
|
||||||
*duration = sample_cnt * profile_period - 1;
|
*duration = sample_cnt * profile_period - 1;
|
||||||
|
@ -607,7 +606,7 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
|
||||||
const unsigned char *in, unsigned size,
|
const unsigned char *in, unsigned size,
|
||||||
struct dive_table *table)
|
struct dive_table *table)
|
||||||
{
|
{
|
||||||
unsigned char *buf = malloc(size);
|
unsigned char *buf = (unsigned char *)malloc(size);
|
||||||
struct dive *dive;
|
struct dive *dive;
|
||||||
struct divecomputer *dc;
|
struct divecomputer *dc;
|
||||||
struct tm tm = {0};
|
struct tm tm = {0};
|
||||||
|
@ -800,26 +799,25 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int try_to_open_cochran(const char *filename, struct memblock *mem, struct divelog *log)
|
int try_to_open_cochran(const char *, std::string &mem, struct divelog *log)
|
||||||
{
|
{
|
||||||
UNUSED(filename);
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int mod;
|
unsigned int mod;
|
||||||
unsigned int *offsets, dive1, dive2;
|
unsigned int *offsets, dive1, dive2;
|
||||||
unsigned char *decode = mem->buffer + 0x40001;
|
unsigned char *decode = (unsigned char *)mem.data() + 0x40001;
|
||||||
|
|
||||||
if (mem->size < 0x40000)
|
if (mem.size() < 0x40000)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
offsets = (unsigned int *) mem->buffer;
|
offsets = (unsigned int *) mem.data();
|
||||||
dive1 = offsets[0];
|
dive1 = offsets[0];
|
||||||
dive2 = offsets[1];
|
dive2 = offsets[1];
|
||||||
|
|
||||||
if (dive1 < 0x40000 || dive2 < dive1 || dive2 > mem->size)
|
if (dive1 < 0x40000 || dive2 < dive1 || dive2 > mem.size())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mod = decode[0x100] + 1;
|
mod = decode[0x100] + 1;
|
||||||
cochran_parse_header(decode, mod, mem->buffer + 0x40000, dive1 - 0x40000);
|
cochran_parse_header(decode, mod, (unsigned char *)mem.data() + 0x40000, dive1 - 0x40000);
|
||||||
|
|
||||||
// Decode each dive
|
// Decode each dive
|
||||||
for (i = 0; i < 65534; i++) {
|
for (i = 0; i < 65534; i++) {
|
||||||
|
@ -827,10 +825,10 @@ int try_to_open_cochran(const char *filename, struct memblock *mem, struct divel
|
||||||
dive2 = offsets[i + 1];
|
dive2 = offsets[i + 1];
|
||||||
if (dive2 < dive1)
|
if (dive2 < dive1)
|
||||||
break;
|
break;
|
||||||
if (dive2 > mem->size)
|
if (dive2 > mem.size())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
cochran_parse_dive(decode, mod, mem->buffer + dive1,
|
cochran_parse_dive(decode, mod, (unsigned char *)mem.data() + dive1,
|
||||||
dive2 - dive1, log->dives);
|
dive2 - dive1, log->dives);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ static char *to_utf8(unsigned char *in_string)
|
||||||
inlen = strlen((char *)in_string);
|
inlen = strlen((char *)in_string);
|
||||||
outlen = inlen * 2 + 1;
|
outlen = inlen * 2 + 1;
|
||||||
|
|
||||||
char *out_string = calloc(outlen, 1);
|
char *out_string = (char *)calloc(outlen, 1);
|
||||||
for (i = 0; i < inlen; i++) {
|
for (i = 0; i < inlen; i++) {
|
||||||
if (in_string[i] < 127) {
|
if (in_string[i] < 127) {
|
||||||
out_string[j] = in_string[i];
|
out_string[j] = in_string[i];
|
||||||
|
@ -158,7 +158,7 @@ static dc_status_t dt_libdc_buffer(unsigned char *ptr, int prf_length, int dc_mo
|
||||||
* Parses a mem buffer extracting its data and filling a subsurface's dive structure.
|
* Parses a mem buffer extracting its data and filling a subsurface's dive structure.
|
||||||
* Returns a pointer to last position in buffer, or NULL on failure.
|
* Returns a pointer to last position in buffer, or NULL on failure.
|
||||||
*/
|
*/
|
||||||
static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct divelog *log, long maxbuf)
|
static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct divelog *log, char *maxbuf)
|
||||||
{
|
{
|
||||||
int rc, profile_length, libdc_model;
|
int rc, profile_length, libdc_model;
|
||||||
char *tmp_notes_str = NULL;
|
char *tmp_notes_str = NULL;
|
||||||
|
@ -174,7 +174,7 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
|
||||||
struct dive_site *ds;
|
struct dive_site *ds;
|
||||||
char is_nitrox = 0, is_O2 = 0, is_SCR = 0;
|
char is_nitrox = 0, is_O2 = 0, is_SCR = 0;
|
||||||
|
|
||||||
device_data_t *devdata = calloc(1, sizeof(device_data_t));
|
device_data_t *devdata = (device_data_t *)calloc(1, sizeof(device_data_t));
|
||||||
devdata->log = log;
|
devdata->log = log;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -478,8 +478,8 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
|
||||||
tmp_notes_str ? tmp_notes_str : "",
|
tmp_notes_str ? tmp_notes_str : "",
|
||||||
QT_TRANSLATE_NOOP("gettextFromC", "Datatrak/Wlog notes"),
|
QT_TRANSLATE_NOOP("gettextFromC", "Datatrak/Wlog notes"),
|
||||||
tmp_string1);
|
tmp_string1);
|
||||||
dt_dive->notes = calloc((len +1), 1);
|
dt_dive->notes = (char *)calloc((len +1), 1);
|
||||||
dt_dive->notes = memcpy(dt_dive->notes, buffer, len);
|
memcpy(dt_dive->notes, buffer, len);
|
||||||
free(tmp_string1);
|
free(tmp_string1);
|
||||||
}
|
}
|
||||||
free(tmp_notes_str);
|
free(tmp_notes_str);
|
||||||
|
@ -571,7 +571,7 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
|
||||||
((get_cylinder(dt_dive, 0)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000);
|
((get_cylinder(dt_dive, 0)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000);
|
||||||
}
|
}
|
||||||
free(devdata);
|
free(devdata);
|
||||||
return membuf;
|
return (char *)membuf;
|
||||||
bail:
|
bail:
|
||||||
free(locality);
|
free(locality);
|
||||||
free(devdata);
|
free(devdata);
|
||||||
|
@ -582,10 +582,10 @@ bail:
|
||||||
* Parses the header of the .add file, returns the number of dives in
|
* Parses the header of the .add file, returns the number of dives in
|
||||||
* the archive (must be the same than number of dives in .log file).
|
* the archive (must be the same than number of dives in .log file).
|
||||||
*/
|
*/
|
||||||
static int wlog_header_parser (struct memblock *mem)
|
static int wlog_header_parser (std::string &mem)
|
||||||
{
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
unsigned char *runner = (unsigned char *) mem->buffer;
|
unsigned char *runner = (unsigned char *) mem.data();
|
||||||
if (!runner)
|
if (!runner)
|
||||||
return -1;
|
return -1;
|
||||||
if (!memcmp(runner, "\x52\x02", 2)) {
|
if (!memcmp(runner, "\x52\x02", 2)) {
|
||||||
|
@ -600,7 +600,7 @@ static int wlog_header_parser (struct memblock *mem)
|
||||||
|
|
||||||
#define NOTES_LENGTH 256
|
#define NOTES_LENGTH 256
|
||||||
#define SUIT_LENGTH 26
|
#define SUIT_LENGTH 26
|
||||||
static void wlog_compl_parser(struct memblock *wl_mem, struct dive *dt_dive, int dcount)
|
static void wlog_compl_parser(std::string &wl_mem, struct dive *dt_dive, int dcount)
|
||||||
{
|
{
|
||||||
int tmp = 0, offset = 12 + (dcount * 850),
|
int tmp = 0, offset = 12 + (dcount * 850),
|
||||||
pos_weight = offset + 256,
|
pos_weight = offset + 256,
|
||||||
|
@ -608,7 +608,7 @@ static void wlog_compl_parser(struct memblock *wl_mem, struct dive *dt_dive, int
|
||||||
pos_tank_init = offset + 266,
|
pos_tank_init = offset + 266,
|
||||||
pos_suit = offset + 268;
|
pos_suit = offset + 268;
|
||||||
char *wlog_notes = NULL, *wlog_suit = NULL, *buffer = NULL;
|
char *wlog_notes = NULL, *wlog_suit = NULL, *buffer = NULL;
|
||||||
unsigned char *runner = (unsigned char *) wl_mem->buffer;
|
unsigned char *runner = (unsigned char *) wl_mem.data();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended notes string. Fixed length 256 bytes. 0 padded if not complete
|
* Extended notes string. Fixed length 256 bytes. 0 padded if not complete
|
||||||
|
@ -620,7 +620,7 @@ static void wlog_compl_parser(struct memblock *wl_mem, struct dive *dt_dive, int
|
||||||
wlog_notes = to_utf8((unsigned char *) wlog_notes_temp);
|
wlog_notes = to_utf8((unsigned char *) wlog_notes_temp);
|
||||||
}
|
}
|
||||||
if (dt_dive->notes && wlog_notes) {
|
if (dt_dive->notes && wlog_notes) {
|
||||||
buffer = calloc (strlen(dt_dive->notes) + strlen(wlog_notes) + 1, 1);
|
buffer = (char *)calloc (strlen(dt_dive->notes) + strlen(wlog_notes) + 1, 1);
|
||||||
sprintf(buffer, "%s%s", dt_dive->notes, wlog_notes);
|
sprintf(buffer, "%s%s", dt_dive->notes, wlog_notes);
|
||||||
free(dt_dive->notes);
|
free(dt_dive->notes);
|
||||||
dt_dive->notes = copy_string(buffer);
|
dt_dive->notes = copy_string(buffer);
|
||||||
|
@ -635,7 +635,7 @@ static void wlog_compl_parser(struct memblock *wl_mem, struct dive *dt_dive, int
|
||||||
*/
|
*/
|
||||||
tmp = (int) two_bytes_to_int(runner[pos_weight + 1], runner[pos_weight]);
|
tmp = (int) two_bytes_to_int(runner[pos_weight + 1], runner[pos_weight]);
|
||||||
if (tmp != 0x7fff) {
|
if (tmp != 0x7fff) {
|
||||||
weightsystem_t ws = { {lrint(tmp * 10)}, QT_TRANSLATE_NOOP("gettextFromC", "unknown"), false };
|
weightsystem_t ws = { {tmp * 10}, QT_TRANSLATE_NOOP("gettextFromC", "unknown"), false };
|
||||||
add_cloned_weightsystem(&dt_dive->weightsystems, ws);
|
add_cloned_weightsystem(&dt_dive->weightsystems, ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,42 +675,40 @@ static void wlog_compl_parser(struct memblock *wl_mem, struct dive *dt_dive, int
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main function call from file.c memblock is allocated (and freed) there.
|
* Main function call from file.c data is allocated (and freed) there.
|
||||||
* If parsing is aborted due to errors, stores correctly parsed dives.
|
* If parsing is aborted due to errors, stores correctly parsed dives.
|
||||||
*/
|
*/
|
||||||
int datatrak_import(struct memblock *mem, struct memblock *wl_mem, struct divelog *log)
|
int datatrak_import(std::string &mem, std::string &wl_mem, struct divelog *log)
|
||||||
{
|
{
|
||||||
unsigned char *runner;
|
char *runner;
|
||||||
int i = 0, numdives = 0, rc = 0;
|
int i = 0, numdives = 0, rc = 0;
|
||||||
|
|
||||||
long maxbuf = (long) mem->buffer + mem->size;
|
char *maxbuf = mem.data() + mem.size();
|
||||||
|
|
||||||
// Verify fileheader, get number of dives in datatrak divelog, zero on error
|
// Verify fileheader, get number of dives in datatrak divelog, zero on error
|
||||||
numdives = read_file_header((unsigned char *)mem->buffer);
|
numdives = read_file_header((unsigned char *)mem.data());
|
||||||
if (!numdives) {
|
if (!numdives) {
|
||||||
report_error(translate("gettextFromC", "[Error] File is not a DataTrak file. Aborted"));
|
report_error(translate("gettextFromC", "[Error] File is not a DataTrak file. Aborted"));
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
// Verify WLog .add file, Beginning sequence and Nº dives
|
// Verify WLog .add file, Beginning sequence and Nº dives
|
||||||
if(wl_mem) {
|
if(!wl_mem.empty()) {
|
||||||
int compl_dives_n = wlog_header_parser(wl_mem);
|
int compl_dives_n = wlog_header_parser(wl_mem);
|
||||||
if (compl_dives_n != numdives) {
|
if (compl_dives_n != numdives) {
|
||||||
report_error("ERROR: Not the same number of dives in .log %d and .add file %d.\nWill not parse .add file", numdives , compl_dives_n);
|
report_error("ERROR: Not the same number of dives in .log %d and .add file %d.\nWill not parse .add file", numdives , compl_dives_n);
|
||||||
free(wl_mem->buffer);
|
wl_mem.clear();
|
||||||
wl_mem->buffer = NULL;
|
|
||||||
wl_mem = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Point to the expected begining of 1st. dive data
|
// Point to the expected begining of 1st. dive data
|
||||||
runner = (unsigned char *)mem->buffer;
|
runner = mem.data();
|
||||||
JUMP(runner, 12);
|
JUMP(runner, 12);
|
||||||
|
|
||||||
// Secuential parsing. Abort if received NULL from dt_dive_parser.
|
// Secuential parsing. Abort if received NULL from dt_dive_parser.
|
||||||
while ((i < numdives) && ((long) runner < maxbuf)) {
|
while ((i < numdives) && (runner < maxbuf)) {
|
||||||
struct dive *ptdive = alloc_dive();
|
struct dive *ptdive = alloc_dive();
|
||||||
|
|
||||||
runner = dt_dive_parser(runner, ptdive, log, maxbuf);
|
runner = dt_dive_parser((unsigned char *)runner, ptdive, log, maxbuf);
|
||||||
if (wl_mem)
|
if (!wl_mem.empty())
|
||||||
wlog_compl_parser(wl_mem, ptdive, i);
|
wlog_compl_parser(wl_mem, ptdive, i);
|
||||||
if (runner == NULL) {
|
if (runner == NULL) {
|
||||||
report_error(translate("gettextFromC", "Error: no dive"));
|
report_error(translate("gettextFromC", "Error: no dive"));
|
|
@ -41,8 +41,8 @@ static const struct models_table_t g_models[] = {
|
||||||
{0xEE, 0x44, "Uwatec Unknown model", DC_FAMILY_UWATEC_ALADIN},
|
{0xEE, 0x44, "Uwatec Unknown model", DC_FAMILY_UWATEC_ALADIN},
|
||||||
};
|
};
|
||||||
|
|
||||||
#define JUMP(_ptr, _n) if ((long) (_ptr += _n) > maxbuf) goto bail
|
#define JUMP(_ptr, _n) if ((char *) (_ptr += _n) > (char *)maxbuf) goto bail
|
||||||
#define CHECK(_ptr, _n) if ((long) _ptr + _n > maxbuf) goto bail
|
#define CHECK(_ptr, _n) if ((char *) _ptr + _n > (char *)maxbuf) goto bail
|
||||||
#define read_bytes(_n) \
|
#define read_bytes(_n) \
|
||||||
switch (_n) { \
|
switch (_n) { \
|
||||||
case 1: \
|
case 1: \
|
||||||
|
@ -62,10 +62,12 @@ static const struct models_table_t g_models[] = {
|
||||||
|
|
||||||
#define read_string(_property) \
|
#define read_string(_property) \
|
||||||
CHECK(membuf, tmp_1byte); \
|
CHECK(membuf, tmp_1byte); \
|
||||||
|
{ \
|
||||||
unsigned char *_property##tmp = (unsigned char *)calloc(tmp_1byte + 1, 1); \
|
unsigned char *_property##tmp = (unsigned char *)calloc(tmp_1byte + 1, 1); \
|
||||||
_property##tmp = memcpy(_property##tmp, membuf, tmp_1byte);\
|
_property##tmp = (unsigned char*)memcpy(_property##tmp, membuf, tmp_1byte);\
|
||||||
_property = (unsigned char *)strcat(to_utf8(_property##tmp), ""); \
|
_property = (unsigned char *)strcat(to_utf8(_property##tmp), ""); \
|
||||||
free(_property##tmp);\
|
free(_property##tmp);\
|
||||||
JUMP(membuf, tmp_1byte);
|
JUMP(membuf, tmp_1byte); \
|
||||||
|
}
|
||||||
|
|
||||||
#endif // DATATRAK_HEADER_H
|
#endif // DATATRAK_HEADER_H
|
||||||
|
|
117
core/file.cpp
117
core/file.cpp
|
@ -31,61 +31,47 @@
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern "C" int readfile(const char *filename, struct memblock *mem)
|
std::pair<std::string, int> readfile(const char *filename)
|
||||||
{
|
{
|
||||||
int ret, fd;
|
int ret, fd;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *buf;
|
|
||||||
|
|
||||||
mem->buffer = NULL;
|
|
||||||
mem->size = 0;
|
|
||||||
|
|
||||||
|
std::string res;
|
||||||
fd = subsurface_open(filename, O_RDONLY | O_BINARY, 0);
|
fd = subsurface_open(filename, O_RDONLY | O_BINARY, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return std::make_pair(res, fd);
|
||||||
ret = fstat(fd, &st);
|
ret = fstat(fd, &st);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
return std::make_pair(res, ret);
|
||||||
ret = -EINVAL;
|
|
||||||
if (!S_ISREG(st.st_mode))
|
if (!S_ISREG(st.st_mode))
|
||||||
goto out;
|
return std::make_pair(res, -EINVAL);
|
||||||
ret = 0;
|
|
||||||
if (!st.st_size)
|
if (!st.st_size)
|
||||||
goto out;
|
return std::make_pair(res, 0);
|
||||||
buf = (char *)malloc(st.st_size + 1);
|
// Sadly, this 0-initializes the string, just before overwriting it.
|
||||||
ret = -1;
|
// However, we use std::string, because that automatically 0-terminates
|
||||||
errno = ENOMEM;
|
// the data and the code expects that.
|
||||||
if (!buf)
|
res.resize(st.st_size);
|
||||||
goto out;
|
ret = read(fd, res.data(), res.size());
|
||||||
mem->buffer = buf;
|
|
||||||
mem->size = st.st_size;
|
|
||||||
ret = read(fd, buf, mem->size);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto free;
|
return std::make_pair(res, ret);
|
||||||
buf[ret] = 0;
|
// converting to int loses a bit but size will never be that big
|
||||||
if (ret == (int)mem->size) // converting to int loses a bit but size will never be that big
|
if (ret == (int)res.size()) {
|
||||||
goto out;
|
return std::make_pair(res, ret);
|
||||||
errno = EIO;
|
} else {
|
||||||
ret = -1;
|
errno = EIO;
|
||||||
free:
|
return std::make_pair(res, -1);
|
||||||
free(mem->buffer);
|
}
|
||||||
mem->buffer = NULL;
|
|
||||||
mem->size = 0;
|
|
||||||
out:
|
|
||||||
close(fd);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void zip_read(struct zip_file *file, const char *filename, struct divelog *log)
|
static void zip_read(struct zip_file *file, const char *filename, struct divelog *log)
|
||||||
{
|
{
|
||||||
int size = 1024, n, read = 0;
|
int size = 1024, n, read = 0;
|
||||||
std::vector<char> mem(size);
|
std::vector<char> mem(size + 1);
|
||||||
|
|
||||||
while ((n = zip_fread(file, mem.data() + read, size - read)) > 0) {
|
while ((n = zip_fread(file, mem.data() + read, size - read)) > 0) {
|
||||||
read += n;
|
read += n;
|
||||||
size = read * 3 / 2;
|
size = read * 3 / 2;
|
||||||
mem.resize(size);
|
mem.resize(size + 1);
|
||||||
}
|
}
|
||||||
mem[read] = 0;
|
mem[read] = 0;
|
||||||
(void) parse_xml_buffer(filename, mem.data(), read, log, NULL);
|
(void) parse_xml_buffer(filename, mem.data(), read, log, NULL);
|
||||||
|
@ -123,7 +109,7 @@ static int db_test_func(void *, int, char **data, char **)
|
||||||
return *data[0] == '0';
|
return *data[0] == '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static int try_to_open_db(const char *filename, struct memblock *mem, struct divelog *log)
|
static int try_to_open_db(const char *filename, std::string &mem, struct divelog *log)
|
||||||
{
|
{
|
||||||
sqlite3 *handle;
|
sqlite3 *handle;
|
||||||
char dm4_test[] = "select count(*) from sqlite_master where type='table' and name='Dive' and sql like '%ProfileBlob%'";
|
char dm4_test[] = "select count(*) from sqlite_master where type='table' and name='Dive' and sql like '%ProfileBlob%'";
|
||||||
|
@ -145,7 +131,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Suunto DM5 database format */
|
/* Testing if DB schema resembles Suunto DM5 database format */
|
||||||
retval = sqlite3_exec(handle, dm5_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, dm5_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_dm5_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_dm5_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -153,7 +139,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Suunto DM4 database format */
|
/* Testing if DB schema resembles Suunto DM4 database format */
|
||||||
retval = sqlite3_exec(handle, dm4_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, dm4_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_dm4_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_dm4_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +147,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Shearwater database format */
|
/* Testing if DB schema resembles Shearwater database format */
|
||||||
retval = sqlite3_exec(handle, shearwater_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, shearwater_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_shearwater_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_shearwater_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +155,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Shearwater cloud database format */
|
/* Testing if DB schema resembles Shearwater cloud database format */
|
||||||
retval = sqlite3_exec(handle, shearwater_cloud_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, shearwater_cloud_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_shearwater_cloud_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_shearwater_cloud_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +163,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Atomic Cobalt database format */
|
/* Testing if DB schema resembles Atomic Cobalt database format */
|
||||||
retval = sqlite3_exec(handle, cobalt_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, cobalt_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_cobalt_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_cobalt_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +171,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Divinglog database format */
|
/* Testing if DB schema resembles Divinglog database format */
|
||||||
retval = sqlite3_exec(handle, divinglog_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, divinglog_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_divinglog_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_divinglog_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -193,7 +179,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
/* Testing if DB schema resembles Seac database format */
|
/* Testing if DB schema resembles Seac database format */
|
||||||
retval = sqlite3_exec(handle, seacsync_test, &db_test_func, 0, NULL);
|
retval = sqlite3_exec(handle, seacsync_test, &db_test_func, 0, NULL);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
retval = parse_seac_buffer(handle, filename, (char *)mem->buffer, mem->size, log);
|
retval = parse_seac_buffer(handle, filename, mem.data(), mem.size(), log);
|
||||||
sqlite3_close(handle);
|
sqlite3_close(handle);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +206,7 @@ static int try_to_open_db(const char *filename, struct memblock *mem, struct div
|
||||||
*
|
*
|
||||||
* Followed by the data values (all comma-separated, all one long line).
|
* Followed by the data values (all comma-separated, all one long line).
|
||||||
*/
|
*/
|
||||||
static int open_by_filename(const char *filename, const char *fmt, struct memblock *mem, struct divelog *log)
|
static int open_by_filename(const char *filename, const char *fmt, std::string &mem, struct divelog *log)
|
||||||
{
|
{
|
||||||
// hack to be able to provide a comment for the translated string
|
// hack to be able to provide a comment for the translated string
|
||||||
static struct { const char *s; const char *comment; } csv_warning =
|
static struct { const char *s; const char *comment; } csv_warning =
|
||||||
|
@ -251,17 +237,17 @@ static int open_by_filename(const char *filename, const char *fmt, struct memblo
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_file_buffer(const char *filename, struct memblock *mem, struct divelog *log)
|
static int parse_file_buffer(const char *filename, std::string &mem, struct divelog *log)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
const char *fmt = strrchr(filename, '.');
|
const char *fmt = strrchr(filename, '.');
|
||||||
if (fmt && (ret = open_by_filename(filename, fmt + 1, mem, log)) != 0)
|
if (fmt && (ret = open_by_filename(filename, fmt + 1, mem, log)) != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!mem->size || !mem->buffer)
|
if (mem.empty())
|
||||||
return report_error("Out of memory parsing file %s\n", filename);
|
return report_error("Out of memory parsing file %s\n", filename);
|
||||||
|
|
||||||
return parse_xml_buffer(filename, (char *)mem->buffer, mem->size, log, NULL);
|
return parse_xml_buffer(filename, mem.data(), mem.size(), log, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" bool remote_repo_uptodate(const char *filename, struct git_info *info)
|
extern "C" bool remote_repo_uptodate(const char *filename, struct git_info *info)
|
||||||
|
@ -284,9 +270,7 @@ extern "C" bool remote_repo_uptodate(const char *filename, struct git_info *info
|
||||||
extern "C" int parse_file(const char *filename, struct divelog *log)
|
extern "C" int parse_file(const char *filename, struct divelog *log)
|
||||||
{
|
{
|
||||||
struct git_info info;
|
struct git_info info;
|
||||||
struct memblock mem;
|
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (is_git_repository(filename, &info)) {
|
if (is_git_repository(filename, &info)) {
|
||||||
if (!open_git_repository(&info)) {
|
if (!open_git_repository(&info)) {
|
||||||
|
@ -300,60 +284,49 @@ extern "C" int parse_file(const char *filename, struct divelog *log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = git_load_dives(&info, log);
|
int ret = git_load_dives(&info, log);
|
||||||
cleanup_git_info(&info);
|
cleanup_git_info(&info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = readfile(filename, &mem)) < 0) {
|
auto [mem, err] = readfile(filename);
|
||||||
|
if (err < 0) {
|
||||||
/* we don't want to display an error if this was the default file */
|
/* we don't want to display an error if this was the default file */
|
||||||
if (same_string(filename, prefs.default_filename))
|
if (same_string(filename, prefs.default_filename))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
||||||
} else if (ret == 0) {
|
} else if (err == 0) {
|
||||||
return report_error(translate("gettextFromC", "Empty file '%s'"), filename);
|
return report_error(translate("gettextFromC", "Empty file '%s'"), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt = strrchr(filename, '.');
|
fmt = strrchr(filename, '.');
|
||||||
if (fmt && (!strcasecmp(fmt + 1, "DB") || !strcasecmp(fmt + 1, "BAK") || !strcasecmp(fmt + 1, "SQL"))) {
|
if (fmt && (!strcasecmp(fmt + 1, "DB") || !strcasecmp(fmt + 1, "BAK") || !strcasecmp(fmt + 1, "SQL"))) {
|
||||||
if (!try_to_open_db(filename, &mem, log)) {
|
if (!try_to_open_db(filename, mem, log))
|
||||||
free(mem.buffer);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Divesoft Freedom */
|
/* Divesoft Freedom */
|
||||||
if (fmt && (!strcasecmp(fmt + 1, "DLF"))) {
|
if (fmt && (!strcasecmp(fmt + 1, "DLF")))
|
||||||
ret = parse_dlf_buffer((unsigned char *)mem.buffer, mem.size, log);
|
return parse_dlf_buffer((unsigned char *)mem.data(), mem.size(), log);
|
||||||
free(mem.buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DataTrak/Wlog */
|
/* DataTrak/Wlog */
|
||||||
if (fmt && !strcasecmp(fmt + 1, "LOG")) {
|
if (fmt && !strcasecmp(fmt + 1, "LOG")) {
|
||||||
struct memblock wl_mem;
|
|
||||||
const char *t = strrchr(filename, '.');
|
const char *t = strrchr(filename, '.');
|
||||||
std::string wl_name = std::string(filename, t - filename) + ".add";
|
std::string wl_name = std::string(filename, t - filename) + ".add";
|
||||||
if((ret = readfile(wl_name.c_str(), &wl_mem)) < 0) {
|
auto [wl_mem, err] = readfile(wl_name.c_str());
|
||||||
|
if (err < 0) {
|
||||||
fprintf(stderr, "No file %s found. No WLog extensions.\n", wl_name.c_str());
|
fprintf(stderr, "No file %s found. No WLog extensions.\n", wl_name.c_str());
|
||||||
ret = datatrak_import(&mem, NULL, log);
|
wl_mem.clear();
|
||||||
} else {
|
|
||||||
ret = datatrak_import(&mem, &wl_mem, log);
|
|
||||||
free(wl_mem.buffer);
|
|
||||||
}
|
}
|
||||||
free(mem.buffer);
|
return datatrak_import(mem, wl_mem, log);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OSTCtools */
|
/* OSTCtools */
|
||||||
if (fmt && (!strcasecmp(fmt + 1, "DIVE"))) {
|
if (fmt && (!strcasecmp(fmt + 1, "DIVE"))) {
|
||||||
free(mem.buffer);
|
|
||||||
ostctools_import(filename, log);
|
ostctools_import(filename, log);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = parse_file_buffer(filename, &mem, log);
|
return parse_file_buffer(filename, mem, log);
|
||||||
free(mem.buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
22
core/file.h
22
core/file.h
|
@ -7,23 +7,14 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
struct memblock {
|
|
||||||
void *buffer;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct divelog;
|
struct divelog;
|
||||||
struct zip;
|
struct zip;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
extern int try_to_open_cochran(const char *filename, struct memblock *mem, struct divelog *log);
|
|
||||||
extern int try_to_open_liquivision(const char *filename, struct memblock *mem, struct divelog *log);
|
|
||||||
extern int datatrak_import(struct memblock *mem, struct memblock *wl_mem, struct divelog *log);
|
|
||||||
extern void ostctools_import(const char *file, struct divelog *log);
|
extern void ostctools_import(const char *file, struct divelog *log);
|
||||||
|
|
||||||
extern int readfile(const char *filename, struct memblock *mem);
|
|
||||||
extern int parse_file(const char *filename, struct divelog *log);
|
extern int parse_file(const char *filename, struct divelog *log);
|
||||||
extern int try_to_open_zip(const char *filename, struct divelog *log);
|
extern int try_to_open_zip(const char *filename, struct divelog *log);
|
||||||
|
|
||||||
|
@ -39,7 +30,20 @@ extern struct zip *subsurface_zip_open_readonly(const char *path, int flags, int
|
||||||
extern int subsurface_zip_close(struct zip *zip);
|
extern int subsurface_zip_close(struct zip *zip);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C++ only functions
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// return data, errorcode pair.
|
||||||
|
extern std::pair<std::string, int> readfile(const char *filename);
|
||||||
|
extern int try_to_open_cochran(const char *filename, std::string &mem, struct divelog *log);
|
||||||
|
extern int try_to_open_liquivision(const char *filename, std::string &mem, struct divelog *log);
|
||||||
|
extern int datatrak_import(std::string &mem, std::string &wl_mem, struct divelog *log);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // FILE_H
|
#endif // FILE_H
|
||||||
|
|
|
@ -106,12 +106,11 @@ static char *parse_dan_new_line(char *buf, const char *NL)
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int try_to_xslt_open_csv(const char *filename, struct memblock *mem, const char *tag);
|
static int try_to_xslt_open_csv(const char *filename, std::string &mem, const char *tag);
|
||||||
static int parse_dan_format(const char *filename, struct xml_params *params, struct divelog *log)
|
static int parse_dan_format(const char *filename, struct xml_params *params, struct divelog *log)
|
||||||
{
|
{
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
size_t end_ptr = 0;
|
size_t end_ptr = 0;
|
||||||
struct memblock mem, mem_csv;
|
|
||||||
char tmpbuf[MAXCOLDIGITS];
|
char tmpbuf[MAXCOLDIGITS];
|
||||||
int params_orig_size = xml_params_count(params);
|
int params_orig_size = xml_params_count(params);
|
||||||
|
|
||||||
|
@ -119,26 +118,24 @@ static int parse_dan_format(const char *filename, struct xml_params *params, str
|
||||||
const char *NL = NULL;
|
const char *NL = NULL;
|
||||||
char *iter = NULL;
|
char *iter = NULL;
|
||||||
|
|
||||||
if (readfile(filename, &mem) < 0)
|
auto [mem, err] = readfile(filename);
|
||||||
|
if (err < 0)
|
||||||
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
||||||
|
|
||||||
/* Determine NL (new line) character and the start of CSV data */
|
/* Determine NL (new line) character and the start of CSV data */
|
||||||
if ((ptr = strstr((char *)mem.buffer, "\r\n")) != NULL) {
|
if ((ptr = strstr(mem.data(), "\r\n")) != NULL) {
|
||||||
NL = "\r\n";
|
NL = "\r\n";
|
||||||
} else if ((ptr = strstr((char *)mem.buffer, "\n")) != NULL) {
|
} else if ((ptr = strstr(mem.data(), "\n")) != NULL) {
|
||||||
NL = "\n";
|
NL = "\n";
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "DEBUG: failed to detect NL\n");
|
fprintf(stderr, "DEBUG: failed to detect NL\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((end_ptr < mem.size) && (ptr = strstr((char *)mem.buffer + end_ptr, "ZDH"))) {
|
while ((end_ptr < mem.size()) && (ptr = strstr(mem.data() + end_ptr, "ZDH"))) {
|
||||||
xml_params_resize(params, params_orig_size); // restart with original parameter block
|
xml_params_resize(params, params_orig_size); // restart with original parameter block
|
||||||
char *iter_end = NULL;
|
char *iter_end = NULL;
|
||||||
|
|
||||||
mem_csv.buffer = malloc(mem.size + 1);
|
|
||||||
mem_csv.size = mem.size;
|
|
||||||
|
|
||||||
iter = ptr + 4;
|
iter = ptr + 4;
|
||||||
iter = strchr(iter, '|');
|
iter = strchr(iter, '|');
|
||||||
if (iter) {
|
if (iter) {
|
||||||
|
@ -195,7 +192,7 @@ static int parse_dan_format(const char *filename, struct xml_params *params, str
|
||||||
|
|
||||||
/* We got a trailer, no samples on this dive */
|
/* We got a trailer, no samples on this dive */
|
||||||
if (strncmp(iter, "ZDT", 3) == 0) {
|
if (strncmp(iter, "ZDT", 3) == 0) {
|
||||||
end_ptr = iter - (char *)mem.buffer;
|
end_ptr = iter - mem.data();
|
||||||
|
|
||||||
/* Water temperature */
|
/* Water temperature */
|
||||||
memset(tmpbuf, 0, sizeof(tmpbuf));
|
memset(tmpbuf, 0, sizeof(tmpbuf));
|
||||||
|
@ -218,7 +215,7 @@ static int parse_dan_format(const char *filename, struct xml_params *params, str
|
||||||
/* After ZDH we should get either ZDT (above) or ZDP */
|
/* After ZDH we should get either ZDT (above) or ZDP */
|
||||||
if (strncmp(iter, "ZDP{", 4) != 0) {
|
if (strncmp(iter, "ZDP{", 4) != 0) {
|
||||||
fprintf(stderr, "DEBUG: Input appears to violate DL7 specification\n");
|
fprintf(stderr, "DEBUG: Input appears to violate DL7 specification\n");
|
||||||
end_ptr = iter - (char *)mem.buffer;
|
end_ptr = iter - mem.data();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,19 +227,20 @@ static int parse_dan_format(const char *filename, struct xml_params *params, str
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
end_ptr = ptr - (char *)mem.buffer;
|
end_ptr = ptr - mem.data();
|
||||||
|
|
||||||
/* Copy the current dive data to start of mem_csv buffer */
|
/* Copy the current dive data to start of mem_csv buffer */
|
||||||
memcpy(mem_csv.buffer, ptr, mem.size - (ptr - (char *)mem.buffer));
|
std::string mem_csv(ptr, mem.size() - (ptr - mem.data()));
|
||||||
ptr = strstr((char *)mem_csv.buffer, "ZDP}");
|
|
||||||
|
ptr = strstr(mem_csv.data(), "ZDP}");
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "DEBUG: failed to find end ZDP\n");
|
fprintf(stderr, "DEBUG: failed to find end ZDP\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
mem_csv.size = ptr - (char*)mem_csv.buffer;
|
mem_csv.resize(ptr - mem_csv.data());
|
||||||
end_ptr += ptr - (char *)mem_csv.buffer;
|
end_ptr += ptr - mem_csv.data();
|
||||||
|
|
||||||
iter = parse_dan_new_line(ptr + 1, NL);
|
iter = parse_dan_new_line(ptr + 1, NL);
|
||||||
if (iter && strncmp(iter, "ZDT", 3) == 0) {
|
if (iter && strncmp(iter, "ZDT", 3) == 0) {
|
||||||
|
@ -262,23 +260,19 @@ static int parse_dan_format(const char *filename, struct xml_params *params, str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try_to_xslt_open_csv(filename, &mem_csv, "csv"))
|
if (try_to_xslt_open_csv(filename, mem_csv, "csv"))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret |= parse_xml_buffer(filename, (char *)mem_csv.buffer, mem_csv.size, log, params);
|
ret |= parse_xml_buffer(filename, mem_csv.data(), mem_csv.size(), log, params);
|
||||||
|
|
||||||
free(mem_csv.buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mem.buffer);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int parse_csv_file(const char *filename, struct xml_params *params, const char *csvtemplate, struct divelog *log)
|
extern "C" int parse_csv_file(const char *filename, struct xml_params *params, const char *csvtemplate, struct divelog *log)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct memblock mem;
|
std::string mem;
|
||||||
time_t now;
|
time_t now;
|
||||||
struct tm *timep = NULL;
|
struct tm *timep = NULL;
|
||||||
char tmpbuf[MAXCOLDIGITS];
|
char tmpbuf[MAXCOLDIGITS];
|
||||||
|
@ -293,7 +287,6 @@ extern "C" int parse_csv_file(const char *filename, struct xml_params *params, c
|
||||||
if (filename == NULL)
|
if (filename == NULL)
|
||||||
return report_error("No CSV filename");
|
return report_error("No CSV filename");
|
||||||
|
|
||||||
mem.size = 0;
|
|
||||||
if (!strcmp("DL7", csvtemplate)) {
|
if (!strcmp("DL7", csvtemplate)) {
|
||||||
return parse_dan_format(filename, params, log);
|
return parse_dan_format(filename, params, log);
|
||||||
} else if (strcmp(xml_params_get_key(params, 0), "date")) {
|
} else if (strcmp(xml_params_get_key(params, 0), "date")) {
|
||||||
|
@ -305,12 +298,11 @@ extern "C" int parse_csv_file(const char *filename, struct xml_params *params, c
|
||||||
|
|
||||||
/* As the parameter is numeric, we need to ensure that the leading zero
|
/* As the parameter is numeric, we need to ensure that the leading zero
|
||||||
* is not discarded during the transform, thus prepend time with 1 */
|
* is not discarded during the transform, thus prepend time with 1 */
|
||||||
|
|
||||||
strftime(tmpbuf, MAXCOLDIGITS, "1%H%M", timep);
|
strftime(tmpbuf, MAXCOLDIGITS, "1%H%M", timep);
|
||||||
xml_params_add(params, "time", tmpbuf);
|
xml_params_add(params, "time", tmpbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try_to_xslt_open_csv(filename, &mem, csvtemplate))
|
if (try_to_xslt_open_csv(filename, mem, csvtemplate))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -327,25 +319,28 @@ extern "C" int parse_csv_file(const char *filename, struct xml_params *params, c
|
||||||
fprintf(stderr, "%s/xslt/%s -\n", SUBSURFACE_SOURCE, csvtemplate);
|
fprintf(stderr, "%s/xslt/%s -\n", SUBSURFACE_SOURCE, csvtemplate);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ret = parse_xml_buffer(filename, (char *)mem.buffer, mem.size, log, params);
|
ret = parse_xml_buffer(filename, mem.data(), mem.size(), log, params);
|
||||||
|
|
||||||
free(mem.buffer);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int try_to_xslt_open_csv(const char *filename, struct memblock *mem, const char *tag)
|
static int try_to_xslt_open_csv(const char *filename, std::string &mem, const char *tag)
|
||||||
{
|
{
|
||||||
char *buf;
|
size_t amp = 0;
|
||||||
size_t i, amp = 0, rest = 0;
|
|
||||||
|
|
||||||
if (mem->size == 0 && readfile(filename, mem) < 0)
|
if (mem.empty()) {
|
||||||
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
auto [mem2, err] = readfile(filename);
|
||||||
|
if (err < 0)
|
||||||
|
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
||||||
|
if (mem2.empty())
|
||||||
|
return 0; // Empty file - nothing to do. Guess that's a "success".
|
||||||
|
mem = std::move(mem2);
|
||||||
|
}
|
||||||
|
|
||||||
/* Count ampersand characters */
|
/* Count ampersand characters */
|
||||||
for (i = 0; i < mem->size; ++i) {
|
for (size_t i = 0; i < mem.size(); ++i) {
|
||||||
if (((char *)mem->buffer)[i] == '&') {
|
if (mem[i] == '&') {
|
||||||
++amp;
|
++amp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,57 +351,49 @@ static int try_to_xslt_open_csv(const char *filename, struct memblock *mem, cons
|
||||||
*
|
*
|
||||||
* Tag markers take: strlen("<></>") = 5
|
* Tag markers take: strlen("<></>") = 5
|
||||||
* Reserve also room for encoding ampersands "&" => "&"
|
* Reserve also room for encoding ampersands "&" => "&"
|
||||||
|
*
|
||||||
|
* Attention: This code is quite subtle, because we reserve one
|
||||||
|
* more byte than we use and put a '\0' there.
|
||||||
*/
|
*/
|
||||||
buf = (char *)realloc((char *)mem->buffer, mem->size + 7 + strlen(tag) * 2 + amp * 4);
|
|
||||||
if (buf != NULL) {
|
|
||||||
char *starttag = NULL;
|
|
||||||
char *endtag = NULL;
|
|
||||||
|
|
||||||
starttag = (char *)malloc(3 + strlen(tag));
|
size_t tag_name_size = strlen(tag);
|
||||||
endtag = (char *)malloc(5 + strlen(tag));
|
size_t old_size = mem.size();
|
||||||
|
mem.resize(mem.size() + tag_name_size * 2 + 5 + amp * 4);
|
||||||
|
const char *ptr_in = mem.data() + old_size;
|
||||||
|
char *ptr_out = mem.data() + mem.size();
|
||||||
|
|
||||||
if (starttag == NULL || endtag == NULL) {
|
/* Add end tag */
|
||||||
/* this is fairly silly - so the malloc fails, but we strdup the error?
|
*--ptr_out = '>';
|
||||||
* let's complete the silliness by freeing the two pointers in case one malloc succeeded
|
ptr_out -= tag_name_size;
|
||||||
* and the other one failed - this will make static analysis tools happy */
|
memcpy(ptr_out, tag, tag_name_size);
|
||||||
free(starttag);
|
*--ptr_out = '/';
|
||||||
free(endtag);
|
*--ptr_out = '<';
|
||||||
free(buf);
|
|
||||||
return report_error("Memory allocation failed in %s", __func__);
|
while (--ptr_in >= mem.data()) {
|
||||||
|
if (*ptr_in == '&') {
|
||||||
|
*--ptr_out = ';';
|
||||||
|
*--ptr_out = 'p';
|
||||||
|
*--ptr_out = 'm';
|
||||||
|
*--ptr_out = 'a';
|
||||||
}
|
}
|
||||||
|
*--ptr_out = *ptr_in;
|
||||||
sprintf(starttag, "<%s>", tag);
|
|
||||||
sprintf(endtag, "\n</%s>", tag);
|
|
||||||
|
|
||||||
memmove(buf + 2 + strlen(tag), buf, mem->size);
|
|
||||||
memcpy(buf, starttag, 2 + strlen(tag));
|
|
||||||
memcpy(buf + mem->size + 2 + strlen(tag), endtag, 5 + strlen(tag));
|
|
||||||
mem->size += (6 + 2 * strlen(tag));
|
|
||||||
mem->buffer = buf;
|
|
||||||
|
|
||||||
free(starttag);
|
|
||||||
free(endtag);
|
|
||||||
|
|
||||||
/* Expand ampersands to encoded version */
|
|
||||||
for (i = mem->size, rest = 0; i > 0; --i, ++rest) {
|
|
||||||
if (((char *)mem->buffer)[i] == '&') {
|
|
||||||
memmove(((char *)mem->buffer) + i + 4 + 1, ((char *)mem->buffer) + i + 1, rest);
|
|
||||||
memcpy(((char *)mem->buffer) + i + 1, "amp;", 4);
|
|
||||||
rest += 4;
|
|
||||||
mem->size += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
free(mem->buffer);
|
|
||||||
return report_error("realloc failed in %s", __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add start tag */
|
||||||
|
*--ptr_out = '>';
|
||||||
|
ptr_out -= tag_name_size;
|
||||||
|
memcpy(ptr_out, tag, tag_name_size);
|
||||||
|
*--ptr_out = '<';
|
||||||
|
|
||||||
|
if (ptr_out != mem.data())
|
||||||
|
fprintf(stderr, "try_to_xslt_open_csv(): ptr_out off by %ld. This shouldn't happen\n", ptr_out - mem.data());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int try_to_open_csv(struct memblock *mem, enum csv_format type, struct divelog *log)
|
int try_to_open_csv(std::string &mem, enum csv_format type, struct divelog *log)
|
||||||
{
|
{
|
||||||
char *p = (char *)mem->buffer;
|
char *p = mem.data();
|
||||||
char *header[8];
|
char *header[8];
|
||||||
int i, time;
|
int i, time;
|
||||||
timestamp_t date;
|
timestamp_t date;
|
||||||
|
@ -498,16 +485,15 @@ static char *next_mkvi_key(char *haystack)
|
||||||
|
|
||||||
int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
|
int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
|
||||||
{
|
{
|
||||||
struct memblock memtxt, memcsv;
|
auto [memtxt, err] = readfile(filename);
|
||||||
|
if (err < 0)
|
||||||
if (readfile(filename, &memtxt) < 0)
|
|
||||||
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MkVI stores some information in .txt file but the whole profile and events are stored in .csv file. First
|
* MkVI stores some information in .txt file but the whole profile and events are stored in .csv file. First
|
||||||
* make sure the input .txt looks like proper MkVI file, then start parsing the .csv.
|
* make sure the input .txt looks like proper MkVI file, then start parsing the .csv.
|
||||||
*/
|
*/
|
||||||
if (MATCH(memtxt.buffer, "MkVI_Config") == 0) {
|
if (MATCH(memtxt.data(), "MkVI_Config") == 0) {
|
||||||
int d, m, y, he;
|
int d, m, y, he;
|
||||||
int hh = 0, mm = 0, ss = 0;
|
int hh = 0, mm = 0, ss = 0;
|
||||||
int prev_depth = 0, cur_sampletime = 0, prev_setpoint = -1, prev_ndl = -1;
|
int prev_depth = 0, cur_sampletime = 0, prev_setpoint = -1, prev_ndl = -1;
|
||||||
|
@ -520,7 +506,7 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
|
||||||
struct divecomputer *dc;
|
struct divecomputer *dc;
|
||||||
struct tm cur_tm;
|
struct tm cur_tm;
|
||||||
|
|
||||||
value = parse_mkvi_value((char *)memtxt.buffer, "Dive started at");
|
value = parse_mkvi_value(memtxt.data(), "Dive started at");
|
||||||
if (sscanf(value, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) != 6) {
|
if (sscanf(value, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) != 6) {
|
||||||
free(value);
|
free(value);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -536,7 +522,7 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
|
||||||
dive = alloc_dive();
|
dive = alloc_dive();
|
||||||
dive->when = utc_mktime(&cur_tm);;
|
dive->when = utc_mktime(&cur_tm);;
|
||||||
dive->dc.model = strdup("Poseidon MkVI Discovery");
|
dive->dc.model = strdup("Poseidon MkVI Discovery");
|
||||||
value = parse_mkvi_value((char *)memtxt.buffer, "Rig Serial number");
|
value = parse_mkvi_value(memtxt.data(), "Rig Serial number");
|
||||||
dive->dc.deviceid = atoi(value);
|
dive->dc.deviceid = atoi(value);
|
||||||
free(value);
|
free(value);
|
||||||
dive->dc.divemode = CCR;
|
dive->dc.divemode = CCR;
|
||||||
|
@ -556,16 +542,16 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
|
||||||
cyl.type.size.mliter = 3000;
|
cyl.type.size.mliter = 3000;
|
||||||
cyl.type.workingpressure.mbar = 200000;
|
cyl.type.workingpressure.mbar = 200000;
|
||||||
cyl.type.description = "3l Mk6";
|
cyl.type.description = "3l Mk6";
|
||||||
value = parse_mkvi_value((char *)memtxt.buffer, "Helium percentage");
|
value = parse_mkvi_value(memtxt.data(), "Helium percentage");
|
||||||
he = atoi(value);
|
he = atoi(value);
|
||||||
free(value);
|
free(value);
|
||||||
value = parse_mkvi_value((char *)memtxt.buffer, "Nitrogen percentage");
|
value = parse_mkvi_value(memtxt.data(), "Nitrogen percentage");
|
||||||
cyl.gasmix.o2.permille = (100 - atoi(value) - he) * 10;
|
cyl.gasmix.o2.permille = (100 - atoi(value) - he) * 10;
|
||||||
free(value);
|
free(value);
|
||||||
cyl.gasmix.he.permille = he * 10;
|
cyl.gasmix.he.permille = he * 10;
|
||||||
add_cloned_cylinder(&dive->cylinders, cyl);
|
add_cloned_cylinder(&dive->cylinders, cyl);
|
||||||
|
|
||||||
lineptr = strstr((char *)memtxt.buffer, "Dive started at");
|
lineptr = strstr(memtxt.data(), "Dive started at");
|
||||||
while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) {
|
while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) {
|
||||||
++lineptr; // Skip over '\n'
|
++lineptr; // Skip over '\n'
|
||||||
key = next_mkvi_key(lineptr);
|
key = next_mkvi_key(lineptr);
|
||||||
|
@ -599,11 +585,12 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
|
||||||
* 39 water temp
|
* 39 water temp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (readfile(csv, &memcsv) < 0) {
|
auto [memcsv, err] = readfile(csv);
|
||||||
|
if (err < 0) {
|
||||||
free_dive(dive);
|
free_dive(dive);
|
||||||
return report_error(translate("gettextFromC", "Poseidon import failed: unable to read '%s'"), csv);
|
return report_error(translate("gettextFromC", "Poseidon import failed: unable to read '%s'"), csv);
|
||||||
}
|
}
|
||||||
lineptr = (char *)memcsv.buffer;
|
lineptr = memcsv.data();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct sample *sample;
|
struct sample *sample;
|
||||||
int type;
|
int type;
|
||||||
|
@ -808,7 +795,6 @@ int parse_seabear_log(const char *filename, struct divelog *log)
|
||||||
static int parse_seabear_csv_file(const char *filename, struct xml_params *params, const char *csvtemplate, struct divelog *log)
|
static int parse_seabear_csv_file(const char *filename, struct xml_params *params, const char *csvtemplate, struct divelog *log)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
struct memblock mem;
|
|
||||||
time_t now;
|
time_t now;
|
||||||
struct tm *timep = NULL;
|
struct tm *timep = NULL;
|
||||||
char *ptr, *ptr_old = NULL;
|
char *ptr, *ptr_old = NULL;
|
||||||
|
@ -836,11 +822,12 @@ static int parse_seabear_csv_file(const char *filename, struct xml_params *param
|
||||||
if (filename == NULL)
|
if (filename == NULL)
|
||||||
return report_error("No CSV filename");
|
return report_error("No CSV filename");
|
||||||
|
|
||||||
if (readfile(filename, &mem) < 0)
|
auto [mem, err] = readfile(filename);
|
||||||
|
if (err < 0)
|
||||||
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
|
||||||
|
|
||||||
/* Determine NL (new line) character and the start of CSV data */
|
/* Determine NL (new line) character and the start of CSV data */
|
||||||
ptr = (char *)mem.buffer;
|
ptr = (char *)mem.data();
|
||||||
while ((ptr = strstr(ptr, "\r\n\r\n")) != NULL) {
|
while ((ptr = strstr(ptr, "\r\n\r\n")) != NULL) {
|
||||||
ptr_old = ptr;
|
ptr_old = ptr;
|
||||||
ptr += 1;
|
ptr += 1;
|
||||||
|
@ -848,7 +835,7 @@ static int parse_seabear_csv_file(const char *filename, struct xml_params *param
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ptr_old) {
|
if (!ptr_old) {
|
||||||
ptr = (char *)mem.buffer;
|
ptr = (char *)mem.data();
|
||||||
while ((ptr = strstr(ptr, "\n\n")) != NULL) {
|
while ((ptr = strstr(ptr, "\n\n")) != NULL) {
|
||||||
ptr_old = ptr;
|
ptr_old = ptr;
|
||||||
ptr += 1;
|
ptr += 1;
|
||||||
|
@ -872,7 +859,7 @@ static int parse_seabear_csv_file(const char *filename, struct xml_params *param
|
||||||
* line and step through from there. That is the line after
|
* line and step through from there. That is the line after
|
||||||
* Serial number.
|
* Serial number.
|
||||||
*/
|
*/
|
||||||
ptr = strstr((char *)mem.buffer, "Serial number:");
|
ptr = strstr((char *)mem.data(), "Serial number:");
|
||||||
if (ptr)
|
if (ptr)
|
||||||
ptr = strstr(ptr, NL);
|
ptr = strstr(ptr, NL);
|
||||||
|
|
||||||
|
@ -904,10 +891,10 @@ static int parse_seabear_csv_file(const char *filename, struct xml_params *param
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move the CSV data to the start of mem buffer */
|
/* Move the CSV data to the start of mem buffer */
|
||||||
memmove(mem.buffer, ptr_old, mem.size - (ptr_old - (char*)mem.buffer));
|
memmove(mem.data(), ptr_old, mem.size() - (ptr_old - mem.data()));
|
||||||
mem.size = (int)mem.size - (ptr_old - (char*)mem.buffer);
|
mem.resize(mem.size() - (ptr_old - mem.data()));
|
||||||
|
|
||||||
if (try_to_xslt_open_csv(filename, &mem, csvtemplate))
|
if (try_to_xslt_open_csv(filename, mem, csvtemplate))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -923,15 +910,14 @@ static int parse_seabear_csv_file(const char *filename, struct xml_params *param
|
||||||
fprintf(stderr, "xslt/csv2xml.xslt\n");
|
fprintf(stderr, "xslt/csv2xml.xslt\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = parse_xml_buffer(filename, (char *)mem.buffer, mem.size, log, params);
|
ret = parse_xml_buffer(filename, mem.data(), mem.size(), log, params);
|
||||||
free(mem.buffer);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_manual_file(const char *filename, struct xml_params *params, struct divelog *log)
|
int parse_manual_file(const char *filename, struct xml_params *params, struct divelog *log)
|
||||||
{
|
{
|
||||||
struct memblock mem;
|
std::string mem;
|
||||||
time_t now;
|
time_t now;
|
||||||
struct tm *timep;
|
struct tm *timep;
|
||||||
char curdate[9];
|
char curdate[9];
|
||||||
|
@ -953,8 +939,7 @@ int parse_manual_file(const char *filename, struct xml_params *params, struct di
|
||||||
if (filename == NULL)
|
if (filename == NULL)
|
||||||
return report_error("No manual CSV filename");
|
return report_error("No manual CSV filename");
|
||||||
|
|
||||||
mem.size = 0;
|
if (try_to_xslt_open_csv(filename, mem, "manualCSV"))
|
||||||
if (try_to_xslt_open_csv(filename, &mem, "manualCSV"))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
#ifndef SUBSURFACE_MOBILE
|
#ifndef SUBSURFACE_MOBILE
|
||||||
|
@ -965,8 +950,7 @@ int parse_manual_file(const char *filename, struct xml_params *params, struct di
|
||||||
fprintf(stderr, "%s/xslt/manualcsv2xml.xslt -\n", SUBSURFACE_SOURCE);
|
fprintf(stderr, "%s/xslt/manualcsv2xml.xslt -\n", SUBSURFACE_SOURCE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ret = parse_xml_buffer(filename, (char *)mem.buffer, mem.size, log, params);
|
ret = parse_xml_buffer(filename, mem.data(), mem.size(), log, params);
|
||||||
|
|
||||||
free(mem.buffer);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int parse_csv_file(const char *filename, struct xml_params *params, const char *csvtemplate, struct divelog *log);
|
int parse_csv_file(const char *filename, struct xml_params *params, const char *csvtemplate, struct divelog *log);
|
||||||
int try_to_open_csv(struct memblock *mem, enum csv_format type, struct divelog *log);
|
int try_to_open_csv(std::string &mem, enum csv_format type, struct divelog *log);
|
||||||
int parse_txt_file(const char *filename, const char *csv, struct divelog *log);
|
int parse_txt_file(const char *filename, const char *csv, struct divelog *log);
|
||||||
|
|
||||||
int parse_seabear_log(const char *filename, struct divelog *log);
|
int parse_seabear_log(const char *filename, struct divelog *log);
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "core/membuffer.h"
|
#include "core/membuffer.h"
|
||||||
#include "core/file.h"
|
#include "core/file.h"
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
char *dumpfile_name;
|
char *dumpfile_name;
|
||||||
char *logfile_name;
|
char *logfile_name;
|
||||||
|
@ -139,7 +140,7 @@ static struct gasmix get_deeper_gasmix(struct gasmix a, struct gasmix b)
|
||||||
* @param ngases The number of gas mixes to process.
|
* @param ngases The number of gas mixes to process.
|
||||||
* @return DC_STATUS_SUCCESS on success, otherwise an error code.
|
* @return DC_STATUS_SUCCESS on success, otherwise an error code.
|
||||||
*/
|
*/
|
||||||
static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t *parser, unsigned int ngases)
|
static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t *parser, unsigned int ngases)
|
||||||
{
|
{
|
||||||
static bool shown_warning = false;
|
static bool shown_warning = false;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -330,7 +331,7 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp
|
||||||
[SAMPLE_EVENT_SAFETYSTOP_MANDATORY] = QT_TRANSLATE_NOOP("gettextFromC", "safety stop (mandatory)"),
|
[SAMPLE_EVENT_SAFETYSTOP_MANDATORY] = QT_TRANSLATE_NOOP("gettextFromC", "safety stop (mandatory)"),
|
||||||
[SAMPLE_EVENT_DEEPSTOP] = QT_TRANSLATE_NOOP("gettextFromC", "deepstop"),
|
[SAMPLE_EVENT_DEEPSTOP] = QT_TRANSLATE_NOOP("gettextFromC", "deepstop"),
|
||||||
[SAMPLE_EVENT_CEILING_SAFETYSTOP] = QT_TRANSLATE_NOOP("gettextFromC", "ceiling (safety stop)"),
|
[SAMPLE_EVENT_CEILING_SAFETYSTOP] = QT_TRANSLATE_NOOP("gettextFromC", "ceiling (safety stop)"),
|
||||||
[SAMPLE_EVENT_FLOOR] = QT_TRANSLATE_NOOP3("gettextFromC", "below floor", "event showing dive is below deco floor and adding deco time"),
|
[SAMPLE_EVENT_FLOOR] = std::array<const char *, 2>{QT_TRANSLATE_NOOP3("gettextFromC", "below floor", "event showing dive is below deco floor and adding deco time")}[1],
|
||||||
[SAMPLE_EVENT_DIVETIME] = QT_TRANSLATE_NOOP("gettextFromC", "divetime"),
|
[SAMPLE_EVENT_DIVETIME] = QT_TRANSLATE_NOOP("gettextFromC", "divetime"),
|
||||||
[SAMPLE_EVENT_MAXDEPTH] = QT_TRANSLATE_NOOP("gettextFromC", "maxdepth"),
|
[SAMPLE_EVENT_MAXDEPTH] = QT_TRANSLATE_NOOP("gettextFromC", "maxdepth"),
|
||||||
[SAMPLE_EVENT_OLF] = QT_TRANSLATE_NOOP("gettextFromC", "OLF"),
|
[SAMPLE_EVENT_OLF] = QT_TRANSLATE_NOOP("gettextFromC", "OLF"),
|
||||||
|
@ -379,7 +380,7 @@ sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata
|
||||||
{
|
{
|
||||||
static unsigned int nsensor = 0;
|
static unsigned int nsensor = 0;
|
||||||
dc_sample_value_t value = *pvalue;
|
dc_sample_value_t value = *pvalue;
|
||||||
struct divecomputer *dc = userdata;
|
struct divecomputer *dc = (divecomputer *)userdata;
|
||||||
struct sample *sample;
|
struct sample *sample;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -494,9 +495,8 @@ sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_info(device_data_t *devdata, const char *fmt, ...)
|
static void dev_info(device_data_t *, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
UNUSED(devdata);
|
|
||||||
static char buffer[1024];
|
static char buffer[1024];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
|
@ -524,9 +524,8 @@ static void download_error(const char *fmt, ...)
|
||||||
report_error("Dive %d: %s", import_dive_number, buffer);
|
report_error("Dive %d: %s", import_dive_number, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_samples(device_data_t *devdata, struct divecomputer *dc, dc_parser_t *parser)
|
static int parse_samples(device_data_t *, struct divecomputer *dc, dc_parser_t *parser)
|
||||||
{
|
{
|
||||||
UNUSED(devdata);
|
|
||||||
// Parse the sample data.
|
// Parse the sample data.
|
||||||
return dc_parser_samples_foreach(parser, sample_cb, dc);
|
return dc_parser_samples_foreach(parser, sample_cb, dc);
|
||||||
}
|
}
|
||||||
|
@ -661,7 +660,7 @@ static void parse_string_field(device_data_t *devdata, struct dive *dive, dc_fie
|
||||||
|
|
||||||
static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devdata, struct dive *dive)
|
static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devdata, struct dive *dive)
|
||||||
{
|
{
|
||||||
dc_status_t rc = 0;
|
dc_status_t rc = static_cast<dc_status_t>(0);
|
||||||
dc_datetime_t dt = { 0 };
|
dc_datetime_t dt = { 0 };
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
|
@ -827,7 +826,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
dc_parser_t *parser = NULL;
|
dc_parser_t *parser = NULL;
|
||||||
device_data_t *devdata = userdata;
|
device_data_t *devdata = (device_data_t *)userdata;
|
||||||
struct dive *dive = NULL;
|
struct dive *dive = NULL;
|
||||||
|
|
||||||
/* reset static data, that is only valid per dive */
|
/* reset static data, that is only valid per dive */
|
||||||
|
@ -873,7 +872,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
|
||||||
* we have the final deviceid here.
|
* we have the final deviceid here.
|
||||||
*/
|
*/
|
||||||
if (fingerprint && fsize && !devdata->fingerprint) {
|
if (fingerprint && fsize && !devdata->fingerprint) {
|
||||||
devdata->fingerprint = calloc(fsize, 1);
|
devdata->fingerprint = (unsigned char *)calloc(fsize, 1);
|
||||||
if (devdata->fingerprint) {
|
if (devdata->fingerprint) {
|
||||||
devdata->fsize = fsize;
|
devdata->fsize = fsize;
|
||||||
devdata->fdeviceid = dive->dc.deviceid;
|
devdata->fdeviceid = dive->dc.deviceid;
|
||||||
|
@ -941,7 +940,7 @@ static void do_save_fingerprint(device_data_t *devdata, const char *tmp, const c
|
||||||
if (close(fd) < 0)
|
if (close(fd) < 0)
|
||||||
written = -1;
|
written = -1;
|
||||||
|
|
||||||
if (written == devdata->fsize) {
|
if (written == (int)devdata->fsize) {
|
||||||
if (!subsurface_rename(tmp, final))
|
if (!subsurface_rename(tmp, final))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1052,7 +1051,6 @@ static void verify_fingerprint(dc_device_t *device, device_data_t *devdata, cons
|
||||||
static void lookup_fingerprint(dc_device_t *device, device_data_t *devdata)
|
static void lookup_fingerprint(dc_device_t *device, device_data_t *devdata)
|
||||||
{
|
{
|
||||||
char *cachename;
|
char *cachename;
|
||||||
struct memblock mem;
|
|
||||||
const unsigned char *raw_data;
|
const unsigned char *raw_data;
|
||||||
|
|
||||||
if (devdata->force_download)
|
if (devdata->force_download)
|
||||||
|
@ -1070,11 +1068,11 @@ static void lookup_fingerprint(dc_device_t *device, device_data_t *devdata)
|
||||||
cachename = fingerprint_file(devdata);
|
cachename = fingerprint_file(devdata);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
dev_info(devdata, "Looking for fingerprint in '%s'", cachename);
|
dev_info(devdata, "Looking for fingerprint in '%s'", cachename);
|
||||||
if (readfile(cachename, &mem) > 0) {
|
auto [mem, err] = readfile(cachename);
|
||||||
|
if (err > 0) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
dev_info(devdata, " ... got %zu bytes", mem.size);
|
dev_info(devdata, " ... got %zu bytes", mem.size());
|
||||||
verify_fingerprint(device, devdata, mem.buffer, mem.size);
|
verify_fingerprint(device, devdata, (unsigned char *)mem.data(), mem.size());
|
||||||
free(mem.buffer);
|
|
||||||
}
|
}
|
||||||
free(cachename);
|
free(cachename);
|
||||||
}
|
}
|
||||||
|
@ -1082,11 +1080,11 @@ static void lookup_fingerprint(dc_device_t *device, device_data_t *devdata)
|
||||||
static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
|
static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
|
||||||
{
|
{
|
||||||
static unsigned int last = 0;
|
static unsigned int last = 0;
|
||||||
const dc_event_progress_t *progress = data;
|
const dc_event_progress_t *progress = (dc_event_progress_t *)data;
|
||||||
const dc_event_devinfo_t *devinfo = data;
|
const dc_event_devinfo_t *devinfo = (dc_event_devinfo_t *)data;
|
||||||
const dc_event_clock_t *clock = data;
|
const dc_event_clock_t *clock = (dc_event_clock_t *)data;
|
||||||
const dc_event_vendor_t *vendor = data;
|
const dc_event_vendor_t *vendor = (dc_event_vendor_t *)data;
|
||||||
device_data_t *devdata = userdata;
|
device_data_t *devdata = (device_data_t *)userdata;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case DC_EVENT_WAITING:
|
case DC_EVENT_WAITING:
|
||||||
|
@ -1158,9 +1156,8 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
|
||||||
|
|
||||||
int import_thread_cancelled;
|
int import_thread_cancelled;
|
||||||
|
|
||||||
static int cancel_cb(void *userdata)
|
static int cancel_cb(void *)
|
||||||
{
|
{
|
||||||
UNUSED(userdata);
|
|
||||||
return import_thread_cancelled;
|
return import_thread_cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1219,9 +1216,8 @@ static const char *do_device_import(device_data_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_timer_t *logfunc_timer = NULL;
|
static dc_timer_t *logfunc_timer = NULL;
|
||||||
void logfunc(dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata)
|
void logfunc(dc_context_t *, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata)
|
||||||
{
|
{
|
||||||
UNUSED(context);
|
|
||||||
const char *loglevels[] = { "NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL" };
|
const char *loglevels[] = { "NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL" };
|
||||||
|
|
||||||
if (logfunc_timer == NULL)
|
if (logfunc_timer == NULL)
|
|
@ -38,13 +38,8 @@ struct lv_sensor_ids {
|
||||||
|
|
||||||
struct lv_sensor_ids sensor_ids;
|
struct lv_sensor_ids sensor_ids;
|
||||||
|
|
||||||
static int handle_event_ver2(int code, const unsigned char *ps, unsigned int ps_ptr, struct lv_event *event)
|
static int handle_event_ver2(int, const unsigned char *, unsigned int, struct lv_event *)
|
||||||
{
|
{
|
||||||
UNUSED(code);
|
|
||||||
UNUSED(ps);
|
|
||||||
UNUSED(ps_ptr);
|
|
||||||
UNUSED(event);
|
|
||||||
|
|
||||||
// Skip 4 bytes
|
// Skip 4 bytes
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +94,7 @@ static int handle_event_ver3(int code, const unsigned char *ps, unsigned int ps_
|
||||||
// 1 byte ST
|
// 1 byte ST
|
||||||
skip = 10;
|
skip = 10;
|
||||||
break;
|
break;
|
||||||
case 0x0010:
|
case 0x0010: {
|
||||||
// 4 byte time
|
// 4 byte time
|
||||||
// 2 byte primary transmitter S/N
|
// 2 byte primary transmitter S/N
|
||||||
// 2 byte buddy transmitter S/N
|
// 2 byte buddy transmitter S/N
|
||||||
|
@ -124,6 +119,7 @@ static int handle_event_ver3(int code, const unsigned char *ps, unsigned int ps_
|
||||||
|
|
||||||
skip = 26;
|
skip = 26;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 0x0015: // Unknown
|
case 0x0015: // Unknown
|
||||||
skip = 2;
|
skip = 2;
|
||||||
break;
|
break;
|
||||||
|
@ -184,7 +180,7 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
|
||||||
place_len = array_uint32_le(buf + ptr + len);
|
place_len = array_uint32_le(buf + ptr + len);
|
||||||
|
|
||||||
if (len && place_len) {
|
if (len && place_len) {
|
||||||
location = malloc(len + place_len + 4);
|
location = (char *)malloc(len + place_len + 4);
|
||||||
memset(location, 0, len + place_len + 4);
|
memset(location, 0, len + place_len + 4);
|
||||||
memcpy(location, buf + ptr, len);
|
memcpy(location, buf + ptr, len);
|
||||||
memcpy(location + len, ", ", 2);
|
memcpy(location + len, ", ", 2);
|
||||||
|
@ -266,8 +262,9 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
|
||||||
sample_interval = intervals[*(buf + ptr)];
|
sample_interval = intervals[*(buf + ptr)];
|
||||||
ptr += 1;
|
ptr += 1;
|
||||||
|
|
||||||
float start_cns = 0;
|
[[maybe_unused]] float start_cns = 0;
|
||||||
unsigned char dive_mode = 0, algorithm = 0;
|
[[maybe_unused]] unsigned char dive_mode = 0;
|
||||||
|
[[maybe_unused]] unsigned char algorithm = 0;
|
||||||
if (array_uint32_le(buf + ptr) != sample_count) {
|
if (array_uint32_le(buf + ptr) != sample_count) {
|
||||||
// Xeo, with CNS and OTU
|
// Xeo, with CNS and OTU
|
||||||
start_cns = *(float *) (buf + ptr);
|
start_cns = *(float *) (buf + ptr);
|
||||||
|
@ -290,9 +287,6 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// we aren't using the start_cns, dive_mode, and algorithm, yet
|
// we aren't using the start_cns, dive_mode, and algorithm, yet
|
||||||
UNUSED(start_cns);
|
|
||||||
UNUSED(dive_mode);
|
|
||||||
UNUSED(algorithm);
|
|
||||||
|
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
|
|
||||||
|
@ -438,11 +432,10 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
|
||||||
free_dive(dive);
|
free_dive(dive);
|
||||||
}
|
}
|
||||||
|
|
||||||
int try_to_open_liquivision(const char *filename, struct memblock *mem, struct divelog *log)
|
int try_to_open_liquivision(const char *, std::string &mem, struct divelog *log)
|
||||||
{
|
{
|
||||||
UNUSED(filename);
|
const unsigned char *buf = (unsigned char *)mem.data();
|
||||||
const unsigned char *buf = mem->buffer;
|
unsigned int buf_size = (unsigned int)mem.size();
|
||||||
unsigned int buf_size = mem->size;
|
|
||||||
unsigned int ptr;
|
unsigned int ptr;
|
||||||
int log_version;
|
int log_version;
|
||||||
|
|
|
@ -237,10 +237,10 @@ void TestParse::testParseNewFormat()
|
||||||
|
|
||||||
void TestParse::testParseDLD()
|
void TestParse::testParseDLD()
|
||||||
{
|
{
|
||||||
struct memblock mem;
|
|
||||||
QString filename = SUBSURFACE_TEST_DATA "/dives/TestDiveDivelogsDE.DLD";
|
QString filename = SUBSURFACE_TEST_DATA "/dives/TestDiveDivelogsDE.DLD";
|
||||||
|
|
||||||
QVERIFY(readfile(filename.toLatin1().data(), &mem) > 0);
|
auto [mem, err] = readfile(filename.toLatin1().data());
|
||||||
|
QVERIFY(err > 0);
|
||||||
QVERIFY(try_to_open_zip(filename.toLatin1().data(), &divelog) > 0);
|
QVERIFY(try_to_open_zip(filename.toLatin1().data(), &divelog) > 0);
|
||||||
|
|
||||||
fprintf(stderr, "number of dives from DLD: %d \n", divelog.dives->nr);
|
fprintf(stderr, "number of dives from DLD: %d \n", divelog.dives->nr);
|
||||||
|
|
Loading…
Add table
Reference in a new issue