This is the oldest format I know for SmartTrak databases. Probably the
first one. It just supports one tank, only air/nitrox and the format of
the database is dramatically different from the other two formats known
to me.
It has different tables, and the "Dives" table differs a lot from newer
versions.
I don't think it's worth to give support for this format, as newer
versions of SmartTrak software automatically comvert the oldest format
to newer one. Thus, finding a lot of this format files is not expected
except from some corner cases of users who had not updated their
SmartTrak software for years now.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
The parser API was very annoying, as a number of tables
to-be-filled were passed in as pointers. The goal of this
commit is to collect all these tables in a single struct.
This should make it (more or less) clear what is actually
written into the divelog files.
Moreover, it should now be rather easy to search for
instances, where the global logfile is accessed (and it
turns out that there are many!).
The divelog struct does not contain the tables as substructs,
but only collects pointers. The idea is that the "divelog.h"
file can be included without all the other files describing
the numerous tables.
To make it easier to use from C++ parts of the code, the
struct implements a constructor and a destructor. Sadly,
we can't use smart pointers, since the pointers are accessed
from C code. Therfore the constructor and destructor are
quite complex.
The whole commit is large, but was mostly an automatic
conversion.
One oddity of note: the divelog structure also contains
the "autogroup" flag, since that is saved in the divelog.
This actually fixes a bug: Before, when importing dives
from a different log, the autogroup flag was overwritten.
This was probably not intended and does not happen anymore.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For reasons of symmetry (there is a is_manually_added_dc()
function), create a make_manually_added_dc() function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The dive was passed as an argument to update_event_name(), but
the divecomputer was derived from the global dc_number variable.
That makes no sense. Therefore, pass the dc_number as argument
and update the only caller (smtk-import).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
With -Wextra, gcc/g++ complains that compound initialization
of weightsystem_t misses the auto_filled parameter. Add it.
For C++ code we might think about writing a constructor. However,
we use two versions: with and without copied string.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This tries to make our fingerprinting code work better, by avoiding
using the "deviceid" field that has always been unreliable because we've
calculated it multiple different ways, and even for the same version of
subsurface, it ends up changing in the middle (ie we calculate one value
initially, then re-calculate it when we have a proper serial number
string).
So instead, the fingerprinting code will look up and save the
fingerprint file using purely "stable" information that is available
early during the download:
- the device model name (which is a string with vendor and product name
separated by a space)
- the DC_EVENT_DEVINFO 32-bit 'serial' number (which is not necessarily
a real serial number at all, but hopefully at least a unique number
for the particular product)
but because the model name is not necessarily a good filename (think
slashes and other possibly invalid characters), we hash that model name
and use the resulting hex number in the fingerprint file name.
This way the fingerprint file is unambiguous at load and save time, and
depends purely on libdivecomputer data.
But because we also need to verify that we have the actual _dive_
associated with that fingerprint, we also need to save the final
deviceid and diveid when saving the fingerprint file, so that when we
load it again we can look up the dive and verify that we have it before
we use the fingerprint data.
To do that, the fingerprint file itself contains not just the
fingerprint data from libdivecomputer, but the last 8 bytes of the file
are the (subsurface) deviceid and the diveid of the dive that is
associated with the fingerprint.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
We have this odd legacy notion of a divecomputer 'device', that was
originally just basically the libdivecomputer 'EVENT_DEVINFO' report
that was associated with each dive. So it had firmware version,
deviceid, and serial number.
It had also gotten extended to do 'nickname' handling, and it was all
confusing, ugly and bad. It was particularly bad because it wasn't
actually a 'per device' thing at all: due to the firmware field, a dive
computer that got a firmware update forced a new 'device'.
To make matters worse, the 'deviceid' was also almost random, because
we've calculated it a couple of different ways, and libdivecomputer
itself has changed how the legacy 32-bit 'serial number' is expressed.
Finally, because of all these issues, we didn't even try to make the
thing unique, so it really ended up being a random snapshot of the state
of the dive computer at the time of a dive, and sometimes we'd pick one,
and sometimes another, since they weren't really well-defined.
So get rid of all this confusion.
The new rules:
- the actual random dive computer state at the time of a dive is kept
in the dive data. So if you want to know the firmware version, it
should be in the 'extra data'
- the only serial number that matters is the string one in the extra
data, because that's the one that actually matches what the dive
computer reports, and isn't some random 32-bit integer with ambiguous
formatting.
- the 'device id' - the thing we match with (together with the model
name, eg "Suunto EON Steel") is purely a hash of the real serial
number.
The device ID that libdivecomputer reports in EVENT_DEVINFO is
ignored, as is the device ID we've saved in the XML or git files. If
we have a serial number, the device ID will be uniquely associated
with that serial number, and if we don't have one, the device ID will
be zero (for 'match anything').
So now 'deviceid' is literally just a shorthand for the serial number
string, and the two are joined at the hip.
- the 'device' managament is _only_ used to track devices that have
serial numbers _and_ nicknames. So no more different device
structures just because one had a nickname and the other didn't etc.
Without a serial number, the device is 'anonymous' and fundamentally
cannot be distinguished from other devices of the same model, so a
nickname is meaningless. And without a nickname, there is no point in
creating a device data structure, since all the data is in the dive
itself and the device structure wouldn't add any value..
These rules mean that we no longer have ambiguous 'device' structures,
and we can never have duplicates that can confuse us.
This does mean that you can't give a nickname to a device that cannot be
uniquely identified with a serial number, but those are happily fairly
rare (and mostly older ones). Dirk said he'd look at what it takes to
give more dive computers proper serial numbers, and I already did it for
the Garmin Descent family yesterday.
(Honesty in advertizing: right now you can't add a nickname to a dive
computer that doesn't already have one, because such a dive computer
will not have a device structure. But that's a UI issue, and I'll sort
that out separately)
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Include devices Ids in the DC data.
Ensure we always set a DC model string for manual dives or unsupported devices.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
In an effort to reduce the size of dive.h and dive.c, break out
the event related functions. Moreover event-names were handled
by the profile-code, collect that also in the new source files.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Smtk2ssrf has a segfault which matches quite well glibc's
CVE-2019-6488 (except for the x32 part).
It came from a call to memcpy in mdb_ole_read() func, used to get the
header and the profile of a dive from the database.
May be it could be fixed in libmdb but Mdbtools project has been stalled
for the past 5 years so ...
The segfault seems to be triggered by an empty profile in the first dive
in the database (a pretty common case in older Aladin DCs due to their
little memmory). The only special thing here is the fact it's the first
dive in the database structure (not the first by its index).
We can avoid the crash if we don't call mdb_ole_read_full() func on zero
sized profile field.
The problem here is we can't get the size of the fields and build the
MdbColumn in the same roud. Happily we just need the MdbColumn struct
for the dive profile and header. So, we can change the previous approach
using MdbColumns through almost all functions to a simpler one using the
already bounded strings by smtk_open_table() and just using the
col[n]->bind_pointer in the main function where the columns are built to
be used by mdb_ole_read_full().
Reported-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
Under some circustances values stored in this arrays may be NULL or even
previously freed. Check them to avoid further crashes.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
The d->cylinders created will be overriden by libdivecomputer parsing,
resulting in 0, 1 , may be 2 cylinders depending on DC data. This is not
what we want when importing a divelog, because we will miss all hand
entered tanks.
BTW, using get_cylinder() on tank number bigger than created, results in
a NULL pointer and a crash.
As we can't foresee how many tanks (or even it's positional numbers in
log) a diver has used, the full 10 tanks supported by SmarTrak can be
easily created and parsed using get_or_create_cylinder(), and unused
cleaned later.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
Grammar-nazi ran
git grep -l 'indexes' | xargs sed -i '' -e 's/indexes/indices/g'
to prevent future wincing when reading the source code.
Unfortunatly, Qt itself is infected as in
QModelIndexList QItemSelection::indexes() const
Signed-off-by: Robert C. Helling <helling@atdotde.de>
Instead of accessing the cylinder table directly, use the get_cylinder()
function. This gives less unwieldy expressions. But more importantly,
the function does bound checking. This is crucial for now as the code
hasn't be properly audited since the change to arbitrarily sized
cylinder tables. Accesses of invalid cylinder indexes may lead to
silent data-corruption that is sometimes not even noticed by
valgrind. Returning NULL instead of an invalid pointer will make
debugging much easier.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of using fixed size arrays, use a new cylinder_table structure.
The code copies the weightsystem code, but is significantly more complex
because cylinders are such an integral part of the core.
Two functions to access the cylinders were added:
get_cylinder() and get_or_create_cylinder()
The former does a simple array access and supposes that the cylinder
exists. The latter is used by the parser(s) and if a cylinder with
the given id does not exist, cylinders up to that id are generated.
One point will make C programmers cringe: the cylinder structure is
passed by value. This is due to the way the table-macros work. A
refactoring of the table macros is planned. It has to be noted that
the size of a cylinder_t is 64 bytes, i.e. 8 long words on a 64-bit
architecture, so passing on the stack is probably not even significantly
slower than passing as reference.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As Berthold points out, a failure to match the site or location index
will result in an infinite loop with previous patch.
With this one the loop will end after reading the last table row even if
no idx is matched. But ... If we asume this situation is possible the
retrieved data would be wrong, and ending the function without filling
the site structure is mandatory too.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
We were assuming these tables were sorted with their indexes, but it
happens to be false, under some circustances at least.
Reported-by: Andreas Hagberg <scubasoft@gmail.com>
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
Replace the fixed-size weightsystem table by a dynamically
relocated table. Reuse the table-macros used in other parts
of the code.
The table stores weightsystem entries, not pointers to
weightsystems. Thus, ownership of the description string is
taken when adding a weightsystem. An extra function adds
a cloned weightsystem at the end of the table.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Make dive.h a bit slimmer. It's only a drop in the bucket - but at
least when modifying tag functions not the *whole* application is
rebuilt anymore.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Remove a few cases of
void fun() {
...
}
While touching these functions, fix a few other whitespace
coding style violations.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since the UUID will be overwritten on save and is only used on save
and load, set it only on save or load. For other created dive sites,
leave the UUID field uninitialized.
This means that the UUID will change between saves. Let's see how
the git saver handles that.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To enable undo of dive site functions, it is crucial to work
with different dive site tables. Therefore add a dive site table
parameter to dive site functions. For now, always pass the global
dive site table. Thus, this commit shouldn't alter any functionality.
After this change, a simple search for dive_site_table reveals all
places where the global dive site table is accessed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
add_to_string() frees the original string that is passed in. This
should therefore not be of "const char *" type, as the contents
of the string *will* be modified (or more precisely: destroyed).
Same for the congener smtk_concat_str().
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Rename
- dive_get_insertion_index() -> dive_table_get_insertion_index()
- unregister_dive_from_table() -> remove_from_dive_table()
- get_idx_in_table() -> get_idx_in_dive_table()
- sort_table() -> sort_dive_table()
This will make it more straight-forward to generate these functions
from macros.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Replace the UUID reference of struct dive by a pointer to dive_site.
This commit is rather large in lines, but nevertheless quite simple
since most of the UUID->pointer work was done in previous commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This changes more of the dive-site interface to return pointers
instead of UUIDs. Currently, most call sites directly extract
UUIDs afterwards. Ultimately, the UUIDs will be generally replaced
by pointers, which will then simplify these callers.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As a first step in removing dive-site uuids, change the interface
of the get_dive_site_*() functions to return pointers instead
of uuids. This makes code a bit more complicated in places where
the uuid is extracted afterwards (needed NULL check). Nevertheless,
these places should disappear once pointers instead of uuids are
stored in the dive-structures.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of having people treat latitude and longitude as separate
things, just add a 'location_t' data structure that contains both.
Almost all cases want to always act on them together.
This is really just prep-work for adding a few more locations that we
track: I want to add a entry/exit location to each dive (independent of
the dive site) because of how the Garmin Descent gives us the
information (and hopefully, some day, other dive computers too).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
And add a fuction to parse tables that are not "relational", meaning
tables which are directly refered from Dives table.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
We can allocate fixed size arrays for smartrak tables as its size can
be known in advance. Simply reading table->num_rows is too dangereous
as smartrak tables have "holes" commonly. This is, they can look like:
Idx | Txt
1 | blablabla
2 | blebleble
4 | blobloblo
table->num_rows would give us 3, but we need to allocate 4 to get an
array like:
|0|blablabla |1|blebleble |2| |3|blobloblo
as the idea is to use the table index to reference the array data.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
Previously we built arrays for the tables each time we parsed a dive.
Now we simply build the lists once, and use them in each dive parsing.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
In most cases we can not foresee the maximum number of data of a given
type. It can be quite low or really big (a concerned diver can store
thousands of different fishes in Fish table).
Moving from arrays, where size has to be preset, to linked lists seems
the more logical option.
Here we set a (very limited) data structure, just an index and a text
fields following the format of most SmartTrak tables. Some special
table, like Buddy, needs a bit of processing before placing the data in
the list.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
In a previous commit, the get_gasmix_* functions were changed to
return by value. For consistency, also pass gasmix by value.
Note that on common 64-bit platforms struct gasmix is the size
of a pointer [2 * 32 bit vs. 64 bit] and therefore uses the
same space on the stack. On 32-bit platforms, the stack use
is probably doubled, but in return a dereference is avoided.
Supporting arbitrary gas-mixes (H2, Ar, ...) will be such an
invasive change that going back to pointers is probably the
least of our worries.
This commit is a step in const-ifying input parameters (passing
by value is the ultimate way of signaling that the input parameter
will not be changed [unless there are references to said parameter]).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Mostly replace "return (expression);" by "return expression;" and one
case of "function((parameter))" by "function(parameter)".
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There are ca. 50 constructs of the kind
same_string(s, "")
to test for empty or null strings. Replace them by the new helper
function empty_string().
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As Lubomir pointed out in his patch for datatrak.c, the format option %m
for sscanf doesn't work in mingw/windows. Fortunately it's unnecessary
as dates are dropped and we just get times.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
For different reasons some used functions aren't portable or simply are
not included in mingw. This includes index, rindex, strptime, and
timegm.
A workaround for this is needed, if we want to build for windows using
mingw based mxe environment. This patch does:
- drops index and rindex in favor of strchr and strrchr
- substitute strptime with a sscanf parsing
- emulate timegm with a private func smtk_timegm()
- remove definitions needed by strptime
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
Curly braces are necessary in nested conditionals or results may not be
those expected. In this case, the "else" clause applied on second "if",
instead of first one.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
SmartTrak's bookmarks work in the same fashion Subsurface's do. The user
may set a bookmark while underwater or set it just on the divelog
software.
At this time we are parsing those set in the DC twice, as we get one
from libdivecomputer and another from smarttrak's database.
This patch just checks if we have a bookmark event downloaded by
libdivecomputer which has the same time that the one parsed from the
.slg file. If so, merge the names taking the one from smarttrak.
Text from smarttrak is preferred because the user may have entered some
interesting note there and libdivecomputer's name is just "bookmark".
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
It was assumed that every data field in a wreck table was filled or
zeroed. This assumption is actually false, so this patch adds testing
for the existence of strings before working with them.
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>