summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/dive.c54
-rw-r--r--core/dive.h14
-rw-r--r--core/equipment.c6
-rw-r--r--core/load-git.c16
-rw-r--r--core/parse-xml.c6
-rw-r--r--core/parse.c15
-rw-r--r--core/parse.h2
-rw-r--r--core/picture.c70
-rw-r--r--core/picture.h22
-rw-r--r--core/save-git.c2
-rw-r--r--core/save-html.c13
-rw-r--r--core/structured_list.h2
-rw-r--r--qt-models/divepicturemodel.cpp4
-rw-r--r--qt-models/divetripmodel.cpp3
-rw-r--r--tests/testpicture.cpp11
15 files changed, 135 insertions, 105 deletions
diff --git a/core/dive.c b/core/dive.c
index defead0a1..abfff2bc5 100644
--- a/core/dive.c
+++ b/core/dive.c
@@ -415,13 +415,6 @@ static void copy_dc_renumber(struct dive *d, const struct divecomputer *sdc, str
ddc->next = NULL;
}
-/* copy an element in a list of pictures */
-static void copy_pl(struct picture *sp, struct picture *dp)
-{
- *dp = *sp;
- dp->filename = copy_string(sp->filename);
-}
-
/* The first divecomputer is embedded in the dive structure. Free its data but not
* the structure itself. For all remainding dcs in the list, free data *and* structures. */
void free_dive_dcs(struct divecomputer *dc)
@@ -443,11 +436,12 @@ static void free_dive_structures(struct dive *d)
/* free tags, additional dive computers, and pictures */
taglist_free(d->tag_list);
free_dive_dcs(&d->dc);
- STRUCTURED_LIST_FREE(struct picture, d->picture_list, free_picture);
clear_cylinder_table(&d->cylinders);
free(d->cylinders.cylinders);
clear_weightsystem_table(&d->weightsystems);
free(d->weightsystems.weightsystems);
+ clear_picture_table(&d->pictures);
+ free(d->pictures.pictures);
}
void free_dive(struct dive *d)
@@ -480,6 +474,7 @@ static void copy_dive_nodc(const struct dive *s, struct dive *d)
*d = *s;
memset(&d->cylinders, 0, sizeof(d->cylinders));
memset(&d->weightsystems, 0, sizeof(d->weightsystems));
+ memset(&d->pictures, 0, sizeof(d->pictures));
d->full_text = NULL;
invalidate_dive_cache(d);
d->buddy = copy_string(s->buddy);
@@ -488,7 +483,7 @@ static void copy_dive_nodc(const struct dive *s, struct dive *d)
d->suit = copy_string(s->suit);
copy_cylinders(&s->cylinders, &d->cylinders);
copy_weights(&s->weightsystems, &d->weightsystems);
- STRUCTURED_LIST_COPY(struct picture, s->picture_list, d->picture_list, copy_pl);
+ copy_pictures(&s->pictures, &d->pictures);
d->tag_list = taglist_copy(s->tag_list);
}
@@ -3062,7 +3057,7 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset,
MERGE_MAX(res, a, b, number);
MERGE_NONZERO(res, a, b, cns);
MERGE_NONZERO(res, a, b, visibility);
- STRUCTURED_LIST_COPY(struct picture, a->picture_list ? a->picture_list : b->picture_list, res->picture_list, copy_pl);
+ copy_pictures(a->pictures.nr ? &a->pictures : &b->pictures, &res->pictures);
taglist_merge(&res->tag_list, a->tag_list, b->tag_list);
cylinders_map_a = malloc(a->cylinders.nr * sizeof(*cylinders_map_a));
cylinders_map_b = malloc(b->cylinders.nr * sizeof(*cylinders_map_b));
@@ -3601,43 +3596,16 @@ void create_picture(const char *filename, int shift_time, bool match_all)
if (!match_all && !dive_check_picture_time(dive, timestamp))
return;
- struct picture *picture = alloc_picture();
- picture->filename = strdup(filename);
- picture->offset.seconds = metadata.timestamp - dive->when + shift_time;
- picture->location = metadata.location;
+ struct picture picture;
+ picture.filename = strdup(filename);
+ picture.offset.seconds = metadata.timestamp - dive->when + shift_time;
+ picture.location = metadata.location;
- dive_add_picture(dive, picture);
- dive_set_geodata_from_picture(dive, picture, &dive_site_table);
+ add_picture(&dive->pictures, picture);
+ dive_set_geodata_from_picture(dive, &picture, &dive_site_table);
invalidate_dive_cache(dive);
}
-void dive_add_picture(struct dive *dive, struct picture *newpic)
-{
- struct picture **pic_ptr = &dive->picture_list;
- /* let's keep the list sorted by time */
- while (*pic_ptr && (*pic_ptr)->offset.seconds <= newpic->offset.seconds)
- pic_ptr = &(*pic_ptr)->next;
- newpic->next = *pic_ptr;
- *pic_ptr = newpic;
- return;
-}
-
-// Return true if picture was found and deleted
-bool dive_remove_picture(struct dive *d, const char *filename)
-{
- struct picture **picture = &d->picture_list;
- while (*picture && !same_string((*picture)->filename, filename))
- picture = &(*picture)->next;
- if (*picture) {
- struct picture *temp = (*picture)->next;
- free_picture(*picture);
- *picture = temp;
- invalidate_dive_cache(d);
- return true;
- }
- return false;
-}
-
/* clones a dive and moves given dive computer to front */
struct dive *make_first_dc(const struct dive *d, int dc_number)
{
diff --git a/core/dive.h b/core/dive.h
index 12b2a102a..33c7c8b0f 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -14,6 +14,7 @@
#include "divemode.h"
#include "equipment.h"
+#include "picture.h"
#ifdef __cplusplus
extern "C" {
@@ -128,7 +129,6 @@ struct divecomputer {
struct divecomputer *next;
};
-struct picture;
struct dive_site;
struct dive_site_table;
struct dive_table;
@@ -160,7 +160,7 @@ struct dive {
struct tag_entry *tag_list;
struct divecomputer dc;
int id; // unique ID for this dive
- struct picture *picture_list;
+ struct picture_table pictures;
unsigned char git_id[20];
bool notrip; /* Don't autogroup this dive to a trip */
bool selected;
@@ -205,12 +205,12 @@ extern struct event *get_next_divemodechange(const struct event **evd, bool upda
extern enum divemode_t get_divemode_at_time(const struct divecomputer *dc, int dtime, const struct event **ev_dmc);
/* picture list and methods related to dive picture handling */
-#define FOR_EACH_PICTURE(_dive) \
- if (_dive) \
- for (struct picture *picture = (_dive)->picture_list; picture; picture = picture->next)
+#define FOR_EACH_PICTURE(_dive) \
+ if ((_dive) && (_dive)->pictures.nr) \
+ for (struct picture *picture = (_dive)->pictures.pictures; \
+ picture < (_dive)->pictures.pictures + (_dive)->pictures.nr; \
+ picture++)
extern void create_picture(const char *filename, int shift_time, bool match_all);
-extern void dive_add_picture(struct dive *d, struct picture *newpic);
-extern bool dive_remove_picture(struct dive *d, const char *filename);
extern bool picture_check_valid_time(timestamp_t timestamp, int shift_time);
extern bool has_gaschange_event(const struct dive *dive, const struct divecomputer *dc, int idx);
diff --git a/core/equipment.c b/core/equipment.c
index 16d6185c1..05e71cee5 100644
--- a/core/equipment.c
+++ b/core/equipment.c
@@ -132,14 +132,14 @@ weightsystem_t clone_weightsystem(weightsystem_t ws)
}
/* Add a clone of a weightsystem to the end of a weightsystem table.
- * Cloned in means that the description-string is copied. */
+ * Cloned means that the description-string is copied. */
void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws)
{
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
}
/* Add a clone of a weightsystem to the end of a weightsystem table.
- * Cloned in means that the description-string is copied. */
+ * Cloned means that the description-string is copied. */
void add_cloned_weightsystem_at(struct weightsystem_table *t, weightsystem_t ws)
{
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
@@ -165,7 +165,7 @@ void add_cylinder(struct cylinder_table *t, int idx, cylinder_t cyl)
}
/* Add a clone of a cylinder to the end of a cylinder table.
- * Cloned in means that the description-string is copied. */
+ * Cloned means that the description-string is copied. */
void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl)
{
add_cylinder(t, t->nr, clone_cylinder(cyl));
diff --git a/core/load-git.c b/core/load-git.c
index ec922d37b..8d3257d0b 100644
--- a/core/load-git.c
+++ b/core/load-git.c
@@ -34,7 +34,7 @@ struct git_parser_state {
struct divecomputer *active_dc;
struct dive *active_dive;
dive_trip_t *active_trip;
- struct picture *active_pic;
+ struct picture active_pic;
struct dive_site *active_site;
struct dive_table *table;
struct trip_table *trips;
@@ -1006,13 +1006,13 @@ static void parse_settings_divecomputerid(char *line, struct membuffer *str, str
static void parse_picture_filename(char *line, struct membuffer *str, struct git_parser_state *state)
{
UNUSED(line);
- state->active_pic->filename = detach_cstring(str);
+ state->active_pic.filename = detach_cstring(str);
}
static void parse_picture_gps(char *line, struct membuffer *str, struct git_parser_state *state)
{
UNUSED(str);
- parse_location(line, &state->active_pic->location);
+ parse_location(line, &state->active_pic.location);
}
static void parse_picture_hash(char *line, struct membuffer *str, struct git_parser_state *state)
@@ -1615,13 +1615,15 @@ static int parse_picture_entry(struct git_parser_state *state, const git_tree_en
if (!blob)
return report_error("Unable to read picture file");
- state->active_pic = alloc_picture();
- state->active_pic->offset.seconds = offset;
+ state->active_pic.offset.seconds = offset;
for_each_line(blob, picture_parser, state);
- dive_add_picture(state->active_dive, state->active_pic);
+ add_picture(&state->active_dive->pictures, state->active_pic);
git_blob_free(blob);
- state->active_pic = NULL;
+
+ /* add_picture took ownership of the data -
+ * clear out our copy just to be sure. */
+ state->active_pic = empty_picture;
return 0;
}
diff --git a/core/parse-xml.c b/core/parse-xml.c
index 164b17b83..4aad15bb5 100644
--- a/core/parse-xml.c
+++ b/core/parse-xml.c
@@ -1258,11 +1258,11 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
if (match_dc_data_fields(&dive->dc, name, buf, state))
return;
- if (MATCH("filename.picture", utf8_string, &state->cur_picture->filename))
+ if (MATCH("filename.picture", utf8_string, &state->cur_picture.filename))
return;
- if (MATCH("offset.picture", offsettime, &state->cur_picture->offset))
+ if (MATCH("offset.picture", offsettime, &state->cur_picture.offset))
return;
- if (MATCH("gps.picture", gps_picture_location, state->cur_picture))
+ if (MATCH("gps.picture", gps_picture_location, &state->cur_picture))
return;
if (MATCH("hash.picture", utf8_string, &hash)) {
/* Legacy -> ignore. */
diff --git a/core/parse.c b/core/parse.c
index be10d65e3..f3b7e0b36 100644
--- a/core/parse.c
+++ b/core/parse.c
@@ -31,7 +31,6 @@ void free_parser_state(struct parser_state *state)
free_dive(state->cur_dive);
free_trip(state->cur_trip);
free_dive_site(state->cur_dive_site);
- free_picture(state->cur_picture);
free((void *)state->cur_extra_data.key);
free((void *)state->cur_extra_data.value);
free((void *)state->cur_settings.dc.model);
@@ -106,11 +105,11 @@ void event_end(struct parser_state *state)
{
struct divecomputer *dc = get_dc(state);
if (state->cur_event.type == 123) {
- struct picture *pic = alloc_picture();
- pic->filename = strdup(state->cur_event.name);
+ struct picture pic;
+ pic.filename = strdup(state->cur_event.name);
/* theoretically this could fail - but we didn't support multi year offsets */
- pic->offset.seconds = state->cur_event.time.seconds;
- dive_add_picture(state->cur_dive, pic);
+ pic.offset.seconds = state->cur_event.time.seconds;
+ add_picture(&state->cur_dive->pictures, pic); /* Takes ownership. */
} else {
struct event *ev;
/* At some point gas change events did not have any type. Thus we need to add
@@ -274,13 +273,13 @@ void trip_end(struct parser_state *state)
void picture_start(struct parser_state *state)
{
- state->cur_picture = alloc_picture();
}
void picture_end(struct parser_state *state)
{
- dive_add_picture(state->cur_dive, state->cur_picture);
- state->cur_picture = NULL;
+ add_picture(&state->cur_dive->pictures, state->cur_picture);
+ /* dive_add_picture took ownership, we can just clear out copy of the data */
+ state->cur_picture = empty_picture;
}
cylinder_t *cylinder_start(struct parser_state *state)
diff --git a/core/parse.h b/core/parse.h
index 56fbff7b4..8886bcd8d 100644
--- a/core/parse.h
+++ b/core/parse.h
@@ -50,7 +50,7 @@ struct parser_state {
location_t cur_location;
struct dive_trip *cur_trip; /* owning */
struct sample *cur_sample; /* non-owning */
- struct picture *cur_picture; /* owning */
+ struct picture cur_picture; /* owning */
char *country, *city; /* owning */
bool in_settings;
diff --git a/core/picture.c b/core/picture.c
index 3f887efe8..727500afd 100644
--- a/core/picture.c
+++ b/core/picture.c
@@ -1,21 +1,71 @@
// SPDX-License-Identifier: GPL-2.0
#include "picture.h"
+#include "table.h"
+#include "subsurface-string.h"
#include <stdlib.h>
#include <string.h>
-struct picture *alloc_picture()
+static void free_picture(struct picture picture)
{
- struct picture *pic = malloc(sizeof(struct picture));
- if (!pic)
- exit(1);
- memset(pic, 0, sizeof(struct picture));
- return pic;
+ free(picture.filename);
+ picture.filename = NULL;
}
-void free_picture(struct picture *picture)
+static int comp_pictures(struct picture a, struct picture b)
{
- if (picture) {
- free(picture->filename);
- free(picture);
+ if (a.offset.seconds < b.offset.seconds)
+ return -1;
+ if (a.offset.seconds > b.offset.seconds)
+ return 1;
+ return strcmp(a.filename ?: "", b.filename ?: "");
+}
+
+static bool picture_less_than(struct picture a, struct picture b)
+{
+ return comp_pictures(a, b) < 0;
+}
+
+/* picture table functions */
+//static MAKE_GET_IDX(picture_table, struct picture, pictures)
+static MAKE_GROW_TABLE(picture_table, struct picture, pictures)
+static MAKE_GET_INSERTION_INDEX(picture_table, struct picture, pictures, picture_less_than)
+MAKE_ADD_TO(picture_table, struct picture, pictures)
+static MAKE_REMOVE_FROM(picture_table, pictures)
+//MAKE_SORT(picture_table, struct picture, pictures, comp_pictures)
+//MAKE_REMOVE(picture_table, struct picture, picture)
+MAKE_CLEAR_TABLE(picture_table, pictures, picture)
+
+/* Add a clone of a picture to the end of a picture table.
+ * Cloned means that the filename-string is copied. */
+static void add_cloned_picture(struct picture_table *t, struct picture pic)
+{
+ pic.filename = copy_string(pic.filename);
+ int idx = picture_table_get_insertion_index(t, pic);
+ add_to_picture_table(t, idx, pic);
+}
+
+void copy_pictures(const struct picture_table *s, struct picture_table *d)
+{
+ int i;
+ clear_picture_table(d);
+ for (i = 0; i < s->nr; i++)
+ add_cloned_picture(d, s->pictures[i]);
+}
+
+void add_picture(struct picture_table *t, struct picture newpic)
+{
+ int idx = picture_table_get_insertion_index(t, newpic);
+ add_to_picture_table(t, idx, newpic);
+}
+
+// Return true if picture was found and deleted
+bool remove_picture(struct picture_table *t, const char *filename)
+{
+ for (int i = 0; i < t->nr; ++i) {
+ if (same_string(t->pictures[i].filename, filename)) {
+ remove_from_picture_table(t, i);
+ return true;
+ }
}
+ return false;
}
diff --git a/core/picture.h b/core/picture.h
index 6dd6650dd..da1a42acd 100644
--- a/core/picture.h
+++ b/core/picture.h
@@ -4,6 +4,7 @@
// picture (more precisely media) related strutures and functions
#include "units.h"
+#include <stddef.h> // For NULL
#ifdef __cplusplus
extern "C" {
@@ -13,11 +14,26 @@ struct picture {
char *filename;
offset_t offset;
location_t location;
- struct picture *next;
};
+static const struct picture empty_picture = { NULL, { 0 }, { { 0 }, { 0 } } };
-extern struct picture *alloc_picture();
-extern void free_picture(struct picture *picture);
+/* Table of pictures. Attention: this stores pictures,
+ * *not* pointers to pictures. This has two crucial consequences:
+ * 1) Pointers to pictures are not stable. They may be
+ * invalidated if the table is reallocated.
+ * 2) add_to_picture_table(), etc. take ownership of the
+ * picture. Notably of the filename. */
+struct picture_table {
+ int nr, allocated;
+ struct picture *pictures;
+};
+
+/* picture table functions */
+extern void clear_picture_table(struct picture_table *);
+extern void add_to_picture_table(struct picture_table *, int idx, struct picture pic);
+extern void copy_pictures(const struct picture_table *s, struct picture_table *d);
+extern void add_picture(struct picture_table *, struct picture newpic);
+extern bool remove_picture(struct picture_table *, const char *filename);
#ifdef __cplusplus
}
diff --git a/core/save-git.c b/core/save-git.c
index 01f804006..ec594f131 100644
--- a/core/save-git.c
+++ b/core/save-git.c
@@ -636,7 +636,7 @@ static int save_one_picture(git_repository *repo, struct dir *dir, struct pictur
static int save_pictures(git_repository *repo, struct dir *dir, struct dive *dive)
{
- if (dive->picture_list) {
+ if (dive->pictures.nr > 0) {
dir = mktree(repo, dir, "Pictures");
FOR_EACH_PICTURE(dive) {
save_one_picture(repo, dir, picture);
diff --git a/core/save-html.c b/core/save-html.c
index 5a01a6d2e..dd4bde130 100644
--- a/core/save-html.c
+++ b/core/save-html.c
@@ -28,23 +28,20 @@ void write_attribute(struct membuffer *b, const char *att_name, const char *valu
void save_photos(struct membuffer *b, const char *photos_dir, struct dive *dive)
{
- struct picture *pic = dive->picture_list;
-
- if (!pic)
+ if (dive->pictures.nr <= 0)
return;
char *separator = "\"photos\":[";
- do {
+ FOR_EACH_PICTURE(dive) {
put_string(b, separator);
separator = ", ";
- char *fname = get_file_name(local_file_path(pic));
+ char *fname = get_file_name(local_file_path(picture));
put_string(b, "{\"filename\":\"");
put_quoted(b, fname, 1, 0);
put_string(b, "\"}");
- copy_image_and_overwrite(local_file_path(pic), photos_dir, fname);
+ copy_image_and_overwrite(local_file_path(picture), photos_dir, fname);
free(fname);
- pic = pic->next;
- } while (pic);
+ }
put_string(b, "],");
}
diff --git a/core/structured_list.h b/core/structured_list.h
index cdf76bb8e..e8fc0d9a2 100644
--- a/core/structured_list.h
+++ b/core/structured_list.h
@@ -2,7 +2,7 @@
#ifndef STRUCTURED_LIST_H
#define STRUCTURED_LIST_H
-/* Clear whole list; this works for taglist, picturelist and dive computers */
+/* Clear whole list; this works for taglist and dive computers */
#define STRUCTURED_LIST_FREE(_type, _start, _free) \
{ \
_type *_ptr = _start; \
diff --git a/qt-models/divepicturemodel.cpp b/qt-models/divepicturemodel.cpp
index 799c49c0e..306030c4e 100644
--- a/qt-models/divepicturemodel.cpp
+++ b/qt-models/divepicturemodel.cpp
@@ -116,8 +116,10 @@ static bool removePictureFromSelectedDive(const char *fileUrl)
int i;
struct dive *dive;
for_each_dive (i, dive) {
- if (dive->selected && dive_remove_picture(dive, fileUrl))
+ if (dive->selected && remove_picture(&dive->pictures, fileUrl)) {
+ invalidate_dive_cache(dive);
return true;
+ }
}
return false;
}
diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp
index 0af987191..73402cdad 100644
--- a/qt-models/divetripmodel.cpp
+++ b/qt-models/divetripmodel.cpp
@@ -302,8 +302,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
}
break;
case PHOTOS:
- if (d->picture_list)
- {
+ if (d->pictures.nr > 0) {
IconMetrics im = defaultIconMetrics();
return QIcon(icon_names[countPhotos(d)]).pixmap(im.sz_small, im.sz_small);
} // If there are photos, show one of the three photo icons: fish= photos during dive;
diff --git a/tests/testpicture.cpp b/tests/testpicture.cpp
index da8fedeec..7bd683523 100644
--- a/tests/testpicture.cpp
+++ b/tests/testpicture.cpp
@@ -31,17 +31,15 @@ void TestPicture::addPicture()
// Pictures will be added to selected dives
dive->selected = true;
QVERIFY(dive != NULL);
- pic1 = dive->picture_list;
// So far no picture in dive
- QVERIFY(pic1 == NULL);
+ QVERIFY(dive->pictures.nr == 0);
create_picture(SUBSURFACE_TEST_DATA "/dives/images/wreck.jpg", 0, false);
create_picture(SUBSURFACE_TEST_DATA "/dives/images/data_after_EOI.jpg", 0, false);
- pic1 = dive->picture_list;
- pic2 = pic1->next;
// Now there are two picture2
- QVERIFY(pic1 != NULL);
- QVERIFY(pic2 != NULL);
+ QVERIFY(dive->pictures.nr == 2);
+ pic1 = &dive->pictures.pictures[0];
+ pic2 = &dive->pictures.pictures[1];
// 1st appearing at time 21:01
// 2nd appearing at time 22:01
QVERIFY(pic1->offset.seconds == 1261);
@@ -55,5 +53,4 @@ void TestPicture::addPicture()
QCOMPARE(localFilePath(pic2->filename), QString(PIC2_NAME));
}
-
QTEST_GUILESS_MAIN(TestPicture)