summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2017-02-19 14:11:37 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2017-02-19 15:23:46 -0800
commit4a550e4d7d5ec11640bb511d28097fa7644cdd3b (patch)
treef89ca8ee5c890a1d185a1f2c8aea8b3e1a0227b6 /core
parentfc55620d2d2942f7f8d95b5e73f8b58ec17ffdb9 (diff)
downloadsubsurface-4a550e4d7d5ec11640bb511d28097fa7644cdd3b.tar.gz
Properly handle dive sites loaded from XML
We used to always create a new dive site structure when loading dive site data from XML. That is completely bogus, because it can (and does) create duplicate dive sites with the same UUID. Which makes the whole UUID pointless. So instead, look up the existing dive site associated with the UUID loaded from the XML, and try to merge the data properly if we already had dive site information for that UUID. Reported-by: Alessandro Volpi <volpial@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'core')
-rw-r--r--core/divesite.c42
-rw-r--r--core/divesite.h1
-rw-r--r--core/parse-xml.c16
3 files changed, 42 insertions, 17 deletions
diff --git a/core/divesite.c b/core/divesite.c
index e9eed2a07..2d7bdbefe 100644
--- a/core/divesite.c
+++ b/core/divesite.c
@@ -2,6 +2,7 @@
#include "divesite.h"
#include "dive.h"
#include "divelist.h"
+#include "membuffer.h"
#include <math.h>
@@ -105,12 +106,10 @@ static uint32_t dive_site_getUniqId()
struct dive_site *alloc_or_get_dive_site(uint32_t uuid)
{
struct dive_site *ds;
- if (uuid) {
- if ((ds = get_dive_site_by_uuid(uuid)) != NULL) {
- fprintf(stderr, "PROBLEM: refusing to create dive site with the same uuid %08x\n", uuid);
- return ds;
- }
- }
+
+ if (uuid && (ds = get_dive_site_by_uuid(uuid)) != NULL)
+ return ds;
+
int nr = dive_site_table.nr;
int allocated = dive_site_table.allocated;
struct dive_site **sites = dive_site_table.dive_sites;
@@ -205,7 +204,6 @@ uint32_t create_dive_site(const char *name, timestamp_t divetime)
uint32_t uuid = create_divesite_uuid(name, divetime);
struct dive_site *ds = alloc_or_get_dive_site(uuid);
ds->name = copy_string(name);
-
return uuid;
}
@@ -273,6 +271,36 @@ void copy_dive_site(struct dive_site *orig, struct dive_site *copy)
}
}
+static void merge_string(char **a, char **b)
+{
+ char *s1 = *a, *s2 = *b;
+
+ if (same_string(s1, s2))
+ return;
+
+ if (!s1) {
+ *a = strdup(s2);
+ return;
+ }
+
+ *a = format_string("(%s) or (%s)", s1, s2);
+ free(s1);
+}
+
+void merge_dive_site(struct dive_site *a, struct dive_site *b)
+{
+ if (!a->latitude.udeg) a->latitude.udeg = b->latitude.udeg;
+ if (!a->longitude.udeg) a->longitude.udeg = b->longitude.udeg;
+ merge_string(&a->name, &b->name);
+ merge_string(&a->notes, &b->notes);
+ merge_string(&a->description, &b->description);
+
+ if (!a->taxonomy.category) {
+ a->taxonomy = b->taxonomy;
+ memset(&b->taxonomy, 0, sizeof(b->taxonomy));
+ }
+}
+
void clear_dive_site(struct dive_site *ds)
{
free(ds->name);
diff --git a/core/divesite.h b/core/divesite.h
index f18b2e8e8..0c38f3556 100644
--- a/core/divesite.h
+++ b/core/divesite.h
@@ -64,6 +64,7 @@ uint32_t get_dive_site_uuid_by_gps_and_name(char *name, degrees_t latitude, degr
uint32_t get_dive_site_uuid_by_gps_proximity(degrees_t latitude, degrees_t longitude, int distance, struct dive_site **dsp);
bool dive_site_is_empty(struct dive_site *ds);
void copy_dive_site(struct dive_site *orig, struct dive_site *copy);
+void merge_dive_site(struct dive_site *a, struct dive_site *b);
void clear_dive_site(struct dive_site *ds);
unsigned int get_distance(degrees_t lat1, degrees_t lon1, degrees_t lat2, degrees_t lon2);
uint32_t find_or_create_dive_site_with_name(const char *name, timestamp_t divetime);
diff --git a/core/parse-xml.c b/core/parse-xml.c
index 44cfece57..0032a5c32 100644
--- a/core/parse-xml.c
+++ b/core/parse-xml.c
@@ -1569,17 +1569,13 @@ static void dive_site_end(void)
{
if (!cur_dive_site)
return;
+ if (cur_dive_site->taxonomy.nr == 0) {
+ free(cur_dive_site->taxonomy.category);
+ cur_dive_site->taxonomy.category = NULL;
+ }
if (cur_dive_site->uuid) {
- // we intentionally call this with '0' to ensure we get
- // a new structure and then copy things into that new
- // structure a few lines below (which sets the correct
- // uuid)
- struct dive_site *ds = alloc_or_get_dive_site(0);
- if (cur_dive_site->taxonomy.nr == 0) {
- free(cur_dive_site->taxonomy.category);
- cur_dive_site->taxonomy.category = NULL;
- }
- copy_dive_site(cur_dive_site, ds);
+ struct dive_site *ds = alloc_or_get_dive_site(cur_dive_site->uuid);
+ merge_dive_site(ds, cur_dive_site);
if (verbose > 3)
printf("completed dive site uuid %x8 name {%s}\n", ds->uuid, ds->name);