Cleanup: Remove hash field from picture-structure

The hash field in the picture-structure was in principle non-operational.
It was set on loading, but never actually changed. The authoritative
hash comes from the filename->hash map.

Therefore, make this explicit by removing the hash field from the
picture structure.

Instead of filling the picture structure on loading, add the
hash directly to the filename->hash map. This is done in the
register_hash() function, which does not overwrite old entries.
I.e. the local hash has priority over the save-file. This
policy might be refined in the future.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2018-02-18 16:22:34 +01:00 committed by Lubomir I. Ivanov
parent e5dcd9fc16
commit bdc470a80e
8 changed files with 61 additions and 46 deletions

View file

@ -1075,10 +1075,20 @@ QMutex hashOfMutex;
QHash<QByteArray, QString> localFilenameOf;
QHash <QString, QImage > thumbnailCache;
extern "C" char * hashstring(const char *filename)
static QByteArray getHash(const QString &filename)
{
QMutexLocker locker(&hashOfMutex);
return strdup(hashOf[QString(filename)].toHex().data());
return hashOf[filename];
}
QString hashString(const char *filename)
{
return getHash(QString(filename)).toHex();
}
extern "C" char * hashstring(const char *filename)
{
return strdup(qPrintable(hashString(filename)));
}
const QString hashfile_name()
@ -1136,6 +1146,21 @@ void add_hash(const QString &filename, const QByteArray &hash)
localFilenameOf[hash] = filename;
}
// Add hash if not already known
extern "C" void register_hash(const char *filename, const char *hash)
{
if (empty_string(filename) || empty_string(hash))
return;
QString filenameString(filename);
QMutexLocker locker(&hashOfMutex);
if (!hashOf.contains(filenameString)) {
QByteArray hashBuf = QByteArray::fromHex(hash);
hashOf[filename] = hashBuf;
localFilenameOf[hashBuf] = filenameString;
}
}
QByteArray hashFile(const QString &filename)
{
QCryptographicHash hash(QCryptographicHash::Sha1);
@ -1174,22 +1199,14 @@ QString localFilePath(const QString &originalFilename)
return originalFilename;
}
QString fileFromHash(const char *hash)
{
if (empty_string(hash))
return "";
QMutexLocker locker(&hashOfMutex);
return localFilenameOf[QByteArray::fromHex(hash)];
}
// This needs to operate on a copy of picture as it frees it after finishing!
void hashPicture(struct picture *picture)
{
if (!picture)
return;
QByteArray oldHash = getHash(QString(picture->filename));
QByteArray hash = hashFile(localFilePath(picture->filename));
if (!hash.isNull() && !same_string(hash.toHex().data(), picture->hash))
if (!hash.isNull() && hash != oldHash)
mark_divelist_changed(true);
picture_free(picture);
}
@ -1230,23 +1247,16 @@ void learnImages(const QDir dir, int max_recursions)
extern "C" const char *local_file_path(struct picture *picture)
{
QString hashString = picture->hash;
if (hashString.isEmpty()) {
QByteArray hash = hashFile(picture->filename);
free(picture->hash);
picture->hash = strdup(hash.toHex().data());
}
QString localFileName = fileFromHash(picture->hash);
if (localFileName.isEmpty())
localFileName = picture->filename;
return strdup(qPrintable(localFileName));
return strdup(qPrintable(localFilePath(picture->filename)));
}
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);
QString localPath = localFilePath(picture->filename);
if (localPath.isEmpty())
return false;
QByteArray hash = hashFile(localPath);
return !hash.isEmpty() && getHash(QString(picture->filename)) == hash;
}
const QString picturedir()
@ -1262,19 +1272,19 @@ extern "C" char *picturedir_string()
/* 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)
extern "C" void savePictureLocal(struct picture *picture, const char *hash, const char *data, int len)
{
QString dirname = picturedir();
QDir localPictureDir(dirname);
localPictureDir.mkpath(dirname);
QString suffix(picture->filename);
suffix.replace(QRegularExpression(".*\\."), "");
QString filename(dirname + picture->hash + "." + suffix);
QString filename(dirname + hash + "." + suffix);
QSaveFile out(filename);
if (out.open(QIODevice::WriteOnly)) {
out.write(data, len);
out.commit();
add_hash(filename, QByteArray::fromHex(picture->hash));
add_hash(filename, QByteArray::fromHex(hash));
}
}