ShatteredPrism/launcher/modplatform/helpers/HashUtils.cpp
Trial97 766ddc80e3
refactored hassing task
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-06-18 16:51:26 +03:00

155 lines
4.2 KiB
C++

#include "HashUtils.h"
#include <QDebug>
#include <QFile>
#include "FileSystem.h"
#include "StringUtils.h"
#include <MurmurHash2.h>
#include <qbuffer.h>
#include <qcryptographichash.h>
#include <qdebug.h>
#include <qfiledevice.h>
namespace Hashing {
Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider)
{
switch (provider) {
case ModPlatform::ResourceProvider::MODRINTH:
return makeShared<Hasher>(file_path,
ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first());
case ModPlatform::ResourceProvider::FLAME:
return makeShared<Hasher>(file_path, Algorithm::Murmur2);
default:
qCritical() << "[Hashing]"
<< "Unrecognized mod platform!";
return nullptr;
}
}
Hasher::Ptr createHasher(QString file_path, QString type)
{
return makeShared<Hasher>(file_path, type);
}
class QIODeviceReader : public Murmur2::Reader {
public:
QIODeviceReader(QIODevice* device) : m_device(device) {}
virtual ~QIODeviceReader() = default;
virtual int read(char* s, int n) { return m_device->read(s, n); }
virtual bool eof() { return m_device->atEnd(); }
virtual void goToBegining() { m_device->seek(0); }
virtual void close() { m_device->close(); }
private:
QIODevice* m_device;
};
QString algorithmToString(Algorithm type)
{
switch (type) {
case Algorithm::Md4:
return "md4";
case Algorithm::Md5:
return "md5";
case Algorithm::Sha1:
return "sha1";
case Algorithm::Sha256:
return "sha256";
case Algorithm::Sha512:
return "sha512";
case Algorithm::Murmur2:
return "murmur2";
// case Algorithm::Unknown:
default:
break;
}
return "unknown";
}
Algorithm algorithmFromString(QString type)
{
if (type == "md4")
return Algorithm::Md4;
if (type == "md5")
return Algorithm::Md5;
if (type == "sha1")
return Algorithm::Sha1;
if (type == "sha256")
return Algorithm::Sha256;
if (type == "sha512")
return Algorithm::Sha512;
if (type == "murmur2")
return Algorithm::Murmur2;
return Algorithm::Unknown;
}
QString hash(QIODevice* device, Algorithm type)
{
if (!device->isOpen() && !device->open(QFile::ReadOnly))
return "";
QCryptographicHash::Algorithm alg = QCryptographicHash::Sha1;
switch (type) {
case Algorithm::Md4:
alg = QCryptographicHash::Algorithm::Md4;
break;
case Algorithm::Md5:
alg = QCryptographicHash::Algorithm::Md5;
break;
case Algorithm::Sha1:
alg = QCryptographicHash::Algorithm::Sha1;
break;
case Algorithm::Sha256:
alg = QCryptographicHash::Algorithm::Sha256;
break;
case Algorithm::Sha512:
alg = QCryptographicHash::Algorithm::Sha512;
break;
case Algorithm::Murmur2: { // CF-specific
auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); };
auto reader = std::make_unique<QIODeviceReader>(device);
auto result = QString::number(Murmur2::hash(reader.get(), 4 * MiB, should_filter_out));
device->close();
return result;
}
case Algorithm::Unknown:
device->close();
return "";
}
QCryptographicHash hash(alg);
if (!hash.addData(device))
qCritical() << "Failed to read JAR to create hash!";
Q_ASSERT(hash.result().length() == hash.hashLength(alg));
auto result = hash.result().toHex();
device->close();
return result;
}
QString hash(QString fileName, Algorithm type)
{
QFile file(fileName);
return hash(&file, type);
}
QString hash(QByteArray data, Algorithm type)
{
QBuffer buff(&data);
return hash(&buff, type);
}
void Hasher::executeTask()
{
m_result = hash(m_path, m_alg);
if (m_result.isEmpty()) {
emitFailed("Empty hash!");
} else {
emitSucceeded();
emit resultsReady(m_result);
}
}
} // namespace Hashing