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:
Berthold Stoeger 2024-03-01 13:09:20 +01:00 committed by Michael Keller
parent 2f4dbf1848
commit cf7c54bd56
12 changed files with 233 additions and 285 deletions

View file

@ -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 \

View file

@ -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

View file

@ -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);
} }

View file

@ -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"));

View file

@ -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

View file

@ -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;
} }

View file

@ -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

View file

@ -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 "&" => "&amp;" * Reserve also room for encoding ampersands "&" => "&amp;"
*
* 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;
} }

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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);