summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2015-06-21 07:43:35 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2015-06-21 12:49:05 -0700
commit31fbc167850572f034c7fbb8551e10e0cfd7ca29 (patch)
treea1f2389eb89263a3d731abd3c4ea5cd5d1d8c7da
parent785f9ba8356203b69672cc76b779b9458ccb9709 (diff)
downloadsubsurface-31fbc167850572f034c7fbb8551e10e0cfd7ca29.tar.gz
Git storage: implement picture loading from git
The interesting challenge here is what to do with the picture data stored in the git repository. If the pictures are already in the file system (for example because Subsurface is runnin on the same machine that this data file was saved on) it would be silly to extract them again every time the dive log is opened. So instead we try to figure out if the pictures can be located and only create local copies of them if that isn't the case. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--load-git.c57
-rw-r--r--qthelper.cpp30
-rw-r--r--qthelperfromc.h2
3 files changed, 88 insertions, 1 deletions
diff --git a/load-git.c b/load-git.c
index 6942b6a41..7cb6c7a0a 100644
--- a/load-git.c
+++ b/load-git.c
@@ -17,9 +17,18 @@
#include "device.h"
#include "membuffer.h"
#include "git-access.h"
+#include "qthelperfromc.h"
const char *saved_git_id = NULL;
+struct picture_entry_list {
+ void *data;
+ int len;
+ const char *hash;
+ struct picture_entry_list *next;
+};
+struct picture_entry_list *pel = NULL;
+
struct keyword_action {
const char *keyword;
void (*fn)(char *, struct membuffer *, void *);
@@ -27,6 +36,21 @@ struct keyword_action {
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
extern degrees_t parse_degrees(char *buf, char **end);
+git_blob *git_tree_entry_blob(git_repository *repo, const git_tree_entry *entry);
+
+static void save_picture_from_git(struct picture *picture)
+{
+ struct picture_entry_list *pic_entry = pel;
+
+ while (pic_entry) {
+ if (same_string(pic_entry->hash, picture->hash)) {
+ savePictureLocal(picture, pic_entry->data, pic_entry->len);
+ return;
+ }
+ pic_entry = pic_entry->next;
+ }
+ fprintf(stderr, "didn't find picture entry for %s\n", picture->filename);
+}
static char *get_utf8(struct membuffer *b)
{
@@ -1069,6 +1093,18 @@ static void finish_active_dive(void)
struct dive *dive = active_dive;
if (dive) {
+ /* check if we need to save pictures */
+ FOR_EACH_PICTURE(dive) {
+ if (!picture_exists(picture))
+ save_picture_from_git(picture);
+ }
+ /* free any memory we allocated to track pictures */
+ while (pel) {
+ free(pel->data);
+ void *lastone = pel;
+ pel = pel->next;
+ free(lastone);
+ }
active_dive = NULL;
record_dive(dive);
}
@@ -1420,6 +1456,23 @@ static int parse_settings_entry(git_repository *repo, const git_tree_entry *entr
return 0;
}
+static int parse_picture_file(git_repository *repo, const git_tree_entry *entry, const char *name)
+{
+ /* remember the picture data so we can handle it when all dive data has been loaded
+ * the name of the git file is PIC-<hash> */
+ git_blob *blob = git_tree_entry_blob(repo, entry);
+ const void *rawdata = git_blob_rawcontent(blob);
+ int len = git_blob_rawsize(blob);
+ struct picture_entry_list *new_pel = malloc(sizeof(struct picture_entry_list));
+ new_pel->next = pel;
+ pel = new_pel;
+ pel->data = malloc(len);
+ memcpy(pel->data, rawdata, len);
+ pel->len = len;
+ pel->hash = strdup(name + 4);
+ git_blob_free(blob);
+}
+
static int parse_picture_entry(git_repository *repo, const git_tree_entry *entry, const char *name)
{
git_blob *blob;
@@ -1480,6 +1533,10 @@ static int walk_tree_file(const char *root, const git_tree_entry *entry, git_rep
if (!strcmp(name, "00-Subsurface"))
return parse_settings_entry(repo, entry);
break;
+ case 'P':
+ if (dive && !strncmp(name, "PIC-", 4))
+ return parse_picture_file(repo, entry, name);
+ break;
}
report_error("Unknown file %s%s (%p %p)", root, name, dive, trip);
return GIT_WALK_SKIP;
diff --git a/qthelper.cpp b/qthelper.cpp
index 3f904d6f1..abf8641ae 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -377,7 +377,8 @@ extern "C" void copy_image_and_overwrite(const char *cfileName, const char *cnew
QFile file(newName);
if (file.exists())
file.remove();
- QFile::copy(fileName, newName);
+ if (!QFile::copy(fileName, newName))
+ qDebug() << "copy of" << fileName << "to" << newName << "failed";
}
extern "C" bool string_sequence_contains(const char *string_sequence, const char *text)
@@ -887,6 +888,33 @@ extern "C" const char *local_file_path(struct picture *picture)
return strdup(qPrintable(localFileName));
}
+extern "C" bool picture_exists(struct picture *picture)
+{
+ QString localFilename = fileFromHash(picture->hash);
+ QByteArray hash = hashFile(localFilename);
+ return same_string(hash.toHex().data(), picture->hash);
+}
+
+/* when we get a picture from git storage (local or remote) and can't find the picture
+ * based on its hash, we create a local copy with the hash as filename and the appropriate
+ * suffix */
+extern "C" void savePictureLocal(struct picture *picture, const char *data, int len)
+{
+ QString dirname(system_default_directory());
+ dirname += "/picturedata/";
+ QDir localPictureDir(dirname);
+ localPictureDir.mkpath(dirname);
+ QString suffix(picture->filename);
+ suffix.replace(QRegularExpression(".*\\."), "");
+ QString filename(dirname + picture->hash + "." + suffix);
+ QSaveFile out(filename);
+ if (out.open(QIODevice::WriteOnly)) {
+ out.write(data, len);
+ out.commit();
+ add_hash(filename, QByteArray::fromHex(picture->hash));
+ }
+}
+
extern "C" void picture_load_exif_data(struct picture *p)
{
EXIFInfo exif;
diff --git a/qthelperfromc.h b/qthelperfromc.h
index 6e8d92b9f..9a5e9551a 100644
--- a/qthelperfromc.h
+++ b/qthelperfromc.h
@@ -9,6 +9,8 @@ void subsurface_mkdir(const char *dir);
char *get_file_name(const char *fileName);
void copy_image_and_overwrite(const char *cfileName, const char *cnewName);
char *hashstring(char *filename);
+bool picture_exists(struct picture *picture);
const char *local_file_path(struct picture *picture);
+void savePictureLocal(struct picture *picture, const char *data, int len);
#endif // QTHELPERFROMC_H