refactored hassing task
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
parent
3f68b68691
commit
766ddc80e3
@ -50,8 +50,6 @@
|
||||
#include "minecraft/mod/tasks/LocalModParseTask.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details()
|
||||
{
|
||||
m_enabled = (file.suffix() != "disabled");
|
||||
@ -250,7 +248,7 @@ void Mod::finishResolvingWithDetails(ModDetails&& details)
|
||||
auto Mod::provider() const -> std::optional<QString>
|
||||
{
|
||||
if (metadata())
|
||||
return ProviderCaps.readableName(metadata()->provider);
|
||||
return ModPlatform::ProviderCapabilities::readableName(metadata()->provider);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
#include "modplatform/modrinth/ModrinthAPI.h"
|
||||
#include "modplatform/modrinth/ModrinthPackIndex.h"
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
static ModrinthAPI modrinth_api;
|
||||
static FlameAPI flame_api;
|
||||
|
||||
@ -162,10 +160,10 @@ void EnsureMetadataTask::executeTask()
|
||||
});
|
||||
|
||||
if (m_mods.size() > 1)
|
||||
setStatus(tr("Requesting metadata information from %1...").arg(ProviderCaps.readableName(m_provider)));
|
||||
setStatus(tr("Requesting metadata information from %1...").arg(ModPlatform::ProviderCapabilities::readableName(m_provider)));
|
||||
else if (!m_mods.empty())
|
||||
setStatus(tr("Requesting metadata information from %1 for '%2'...")
|
||||
.arg(ProviderCaps.readableName(m_provider), m_mods.begin().value()->name()));
|
||||
.arg(ModPlatform::ProviderCapabilities::readableName(m_provider), m_mods.begin().value()->name()));
|
||||
|
||||
m_current_task = version_task;
|
||||
version_task->start();
|
||||
@ -215,7 +213,7 @@ void EnsureMetadataTask::emitFail(Mod* m, QString key, RemoveFromList remove)
|
||||
|
||||
Task::Ptr EnsureMetadataTask::modrinthVersionsTask()
|
||||
{
|
||||
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
auto hash_type = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
auto ver_task = modrinth_api.currentVersions(m_mods.keys(), hash_type, response);
|
||||
|
@ -59,7 +59,7 @@ IndexedVersionType::VersionType IndexedVersionType::enumFromString(const QString
|
||||
return s_indexed_version_type_names.value(type, IndexedVersionType::VersionType::Unknown);
|
||||
}
|
||||
|
||||
auto ProviderCapabilities::name(ResourceProvider p) -> const char*
|
||||
const char* ProviderCapabilities::name(ResourceProvider p)
|
||||
{
|
||||
switch (p) {
|
||||
case ResourceProvider::MODRINTH:
|
||||
@ -69,7 +69,8 @@ auto ProviderCapabilities::name(ResourceProvider p) -> const char*
|
||||
}
|
||||
return {};
|
||||
}
|
||||
auto ProviderCapabilities::readableName(ResourceProvider p) -> QString
|
||||
|
||||
QString ProviderCapabilities::readableName(ResourceProvider p)
|
||||
{
|
||||
switch (p) {
|
||||
case ResourceProvider::MODRINTH:
|
||||
@ -79,7 +80,8 @@ auto ProviderCapabilities::readableName(ResourceProvider p) -> QString
|
||||
}
|
||||
return {};
|
||||
}
|
||||
auto ProviderCapabilities::hashType(ResourceProvider p) -> QStringList
|
||||
|
||||
QStringList ProviderCapabilities::hashType(ResourceProvider p)
|
||||
{
|
||||
switch (p) {
|
||||
case ResourceProvider::MODRINTH:
|
||||
@ -91,26 +93,6 @@ auto ProviderCapabilities::hashType(ResourceProvider p) -> QStringList
|
||||
return {};
|
||||
}
|
||||
|
||||
auto ProviderCapabilities::hash(ResourceProvider p, QIODevice* device, QString type) -> QString
|
||||
{
|
||||
QCryptographicHash::Algorithm algo = QCryptographicHash::Sha1;
|
||||
switch (p) {
|
||||
case ResourceProvider::MODRINTH:
|
||||
algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Sha512;
|
||||
break;
|
||||
case ResourceProvider::FLAME:
|
||||
algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Md5;
|
||||
break;
|
||||
}
|
||||
|
||||
QCryptographicHash hash(algo);
|
||||
if (!hash.addData(device))
|
||||
qCritical() << "Failed to read JAR to create hash!";
|
||||
|
||||
Q_ASSERT(hash.result().length() == hash.hashLength(algo));
|
||||
return { hash.result().toHex() };
|
||||
}
|
||||
|
||||
QString getMetaURL(ResourceProvider provider, QVariant projectID)
|
||||
{
|
||||
return ((provider == ModPlatform::ResourceProvider::FLAME) ? "https://www.curseforge.com/projects/" : "https://modrinth.com/mod/") +
|
||||
|
@ -40,13 +40,11 @@ enum class ResourceType { MOD, RESOURCE_PACK, SHADER_PACK };
|
||||
|
||||
enum class DependencyType { REQUIRED, OPTIONAL, INCOMPATIBLE, EMBEDDED, TOOL, INCLUDE, UNKNOWN };
|
||||
|
||||
class ProviderCapabilities {
|
||||
public:
|
||||
auto name(ResourceProvider) -> const char*;
|
||||
auto readableName(ResourceProvider) -> QString;
|
||||
auto hashType(ResourceProvider) -> QStringList;
|
||||
auto hash(ResourceProvider, QIODevice*, QString type = "") -> QString;
|
||||
};
|
||||
namespace ProviderCapabilities {
|
||||
const char* name(ResourceProvider);
|
||||
QString readableName(ResourceProvider);
|
||||
QStringList hashType(ResourceProvider);
|
||||
}; // namespace ProviderCapabilities
|
||||
|
||||
struct ModpackAuthor {
|
||||
QString name;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "modplatform/flame/FlameAPI.h"
|
||||
|
||||
static FlameAPI api;
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
{
|
||||
@ -161,7 +160,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
|
||||
auto hash_list = Json::ensureArray(obj, "hashes");
|
||||
for (auto h : hash_list) {
|
||||
auto hash_entry = Json::ensureObject(h);
|
||||
auto hash_types = ProviderCaps.hashType(ModPlatform::ResourceProvider::FLAME);
|
||||
auto hash_types = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::FLAME);
|
||||
auto hash_algo = enumToString(Json::ensureInteger(hash_entry, "algo", 1, "algorithm"));
|
||||
if (hash_types.contains(hash_algo)) {
|
||||
file.hash = Json::requireString(hash_entry, "value");
|
||||
|
@ -116,7 +116,7 @@ void FlamePackExportTask::collectHashes()
|
||||
|
||||
if (relative.startsWith("resourcepacks/") &&
|
||||
(relative.endsWith(".zip") || relative.endsWith(".zip.disabled"))) { // is resourcepack
|
||||
auto hashTask = Hashing::createFlameHasher(file.absoluteFilePath());
|
||||
auto hashTask = Hashing::createHasher(file.absoluteFilePath(), ModPlatform::ResourceProvider::FLAME);
|
||||
connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, relative, file](QString hash) {
|
||||
if (m_state == Task::State::Running) {
|
||||
pendingHashes.insert(hash, { relative, file.absoluteFilePath(), relative.endsWith(".zip") });
|
||||
@ -140,7 +140,7 @@ void FlamePackExportTask::collectHashes()
|
||||
continue;
|
||||
}
|
||||
|
||||
auto hashTask = Hashing::createFlameHasher(mod->fileinfo().absoluteFilePath());
|
||||
auto hashTask = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::FLAME);
|
||||
connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) {
|
||||
if (m_state == Task::State::Running) {
|
||||
pendingHashes.insert(hash, { mod->name(), mod->fileinfo().absoluteFilePath(), mod->enabled(), true });
|
||||
|
@ -7,18 +7,21 @@
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <MurmurHash2.h>
|
||||
#include <qbuffer.h>
|
||||
#include <qcryptographichash.h>
|
||||
#include <qdebug.h>
|
||||
#include <qfiledevice.h>
|
||||
|
||||
namespace Hashing {
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider)
|
||||
{
|
||||
switch (provider) {
|
||||
case ModPlatform::ResourceProvider::MODRINTH:
|
||||
return createModrinthHasher(file_path);
|
||||
return makeShared<Hasher>(file_path,
|
||||
ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first());
|
||||
case ModPlatform::ResourceProvider::FLAME:
|
||||
return createFlameHasher(file_path);
|
||||
return makeShared<Hasher>(file_path, Algorithm::Murmur2);
|
||||
default:
|
||||
qCritical() << "[Hashing]"
|
||||
<< "Unrecognized mod platform!";
|
||||
@ -26,119 +29,126 @@ Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provid
|
||||
}
|
||||
}
|
||||
|
||||
Hasher::Ptr createModrinthHasher(QString file_path)
|
||||
Hasher::Ptr createHasher(QString file_path, QString type)
|
||||
{
|
||||
return makeShared<ModrinthHasher>(file_path);
|
||||
return makeShared<Hasher>(file_path, type);
|
||||
}
|
||||
|
||||
Hasher::Ptr createFlameHasher(QString file_path)
|
||||
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)
|
||||
{
|
||||
return makeShared<FlameHasher>(file_path);
|
||||
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";
|
||||
}
|
||||
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider)
|
||||
Algorithm algorithmFromString(QString type)
|
||||
{
|
||||
return makeShared<BlockedModHasher>(file_path, provider);
|
||||
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;
|
||||
}
|
||||
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider, QString type)
|
||||
QString hash(QIODevice* device, Algorithm type)
|
||||
{
|
||||
auto hasher = makeShared<BlockedModHasher>(file_path, provider);
|
||||
hasher->useHashType(type);
|
||||
return hasher;
|
||||
}
|
||||
|
||||
void ModrinthHasher::executeTask()
|
||||
{
|
||||
QFile file(m_path);
|
||||
|
||||
try {
|
||||
file.open(QFile::ReadOnly);
|
||||
} catch (FS::FileSystemException& e) {
|
||||
qCritical() << QString("Failed to open JAR file in %1").arg(m_path);
|
||||
qCritical() << QString("Reason: ") << e.cause();
|
||||
|
||||
emitFailed("Failed to open file for hashing.");
|
||||
return;
|
||||
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 "";
|
||||
}
|
||||
|
||||
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
m_hash = ProviderCaps.hash(ModPlatform::ResourceProvider::MODRINTH, &file, hash_type);
|
||||
QCryptographicHash hash(alg);
|
||||
if (!hash.addData(device))
|
||||
qCritical() << "Failed to read JAR to create hash!";
|
||||
|
||||
file.close();
|
||||
Q_ASSERT(hash.result().length() == hash.hashLength(alg));
|
||||
auto result = hash.result().toHex();
|
||||
device->close();
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_hash.isEmpty()) {
|
||||
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_hash);
|
||||
emit resultsReady(m_result);
|
||||
}
|
||||
}
|
||||
|
||||
void FlameHasher::executeTask()
|
||||
{
|
||||
// CF-specific
|
||||
auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); };
|
||||
|
||||
std::ifstream file_stream(StringUtils::toStdString(m_path).c_str(), std::ifstream::binary);
|
||||
// TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread.
|
||||
// How do we make this non-blocking then?
|
||||
m_hash = QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out));
|
||||
|
||||
if (m_hash.isEmpty()) {
|
||||
emitFailed("Empty hash!");
|
||||
} else {
|
||||
emitSucceeded();
|
||||
emit resultsReady(m_hash);
|
||||
}
|
||||
}
|
||||
|
||||
BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider) : Hasher(file_path), provider(provider)
|
||||
{
|
||||
setObjectName(QString("BlockedModHasher: %1").arg(file_path));
|
||||
hash_type = ProviderCaps.hashType(provider).first();
|
||||
}
|
||||
|
||||
void BlockedModHasher::executeTask()
|
||||
{
|
||||
QFile file(m_path);
|
||||
|
||||
try {
|
||||
file.open(QFile::ReadOnly);
|
||||
} catch (FS::FileSystemException& e) {
|
||||
qCritical() << QString("Failed to open JAR file in %1").arg(m_path);
|
||||
qCritical() << QString("Reason: ") << e.cause();
|
||||
|
||||
emitFailed("Failed to open file for hashing.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_hash = ProviderCaps.hash(provider, &file, hash_type);
|
||||
|
||||
file.close();
|
||||
|
||||
if (m_hash.isEmpty()) {
|
||||
emitFailed("Empty hash!");
|
||||
} else {
|
||||
emitSucceeded();
|
||||
emit resultsReady(m_hash);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList BlockedModHasher::getHashTypes()
|
||||
{
|
||||
return ProviderCaps.hashType(provider);
|
||||
}
|
||||
|
||||
bool BlockedModHasher::useHashType(QString type)
|
||||
{
|
||||
auto types = ProviderCaps.hashType(provider);
|
||||
if (types.contains(type)) {
|
||||
hash_type = type;
|
||||
return true;
|
||||
}
|
||||
qDebug() << "Bad hash type " << type << " for provider";
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Hashing
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QString>
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
@ -7,61 +8,40 @@
|
||||
|
||||
namespace Hashing {
|
||||
|
||||
enum class Algorithm { Md4, Md5, Sha1, Sha256, Sha512, Murmur2, Unknown };
|
||||
|
||||
QString algorithmToString(Algorithm type);
|
||||
Algorithm algorithmFromString(QString type);
|
||||
QString hash(QIODevice* device, Algorithm type);
|
||||
QString hash(QString fileName, Algorithm type);
|
||||
QString hash(QByteArray data, Algorithm type);
|
||||
|
||||
class Hasher : public Task {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using Ptr = shared_qobject_ptr<Hasher>;
|
||||
|
||||
Hasher(QString file_path) : m_path(std::move(file_path)) {}
|
||||
Hasher(QString file_path, Algorithm alg) : m_path(file_path), m_alg(alg) {}
|
||||
Hasher(QString file_path, QString alg) : Hasher(file_path, algorithmFromString(alg)) {}
|
||||
|
||||
/* We can't really abort this task, but we can say we aborted and finish our thing quickly :) */
|
||||
bool abort() override { return true; }
|
||||
|
||||
void executeTask() override = 0;
|
||||
void executeTask() override;
|
||||
|
||||
QString getResult() const { return m_hash; };
|
||||
QString getResult() const { return m_result; };
|
||||
QString getPath() const { return m_path; };
|
||||
|
||||
signals:
|
||||
void resultsReady(QString hash);
|
||||
|
||||
protected:
|
||||
QString m_hash;
|
||||
QString m_result;
|
||||
QString m_path;
|
||||
};
|
||||
|
||||
class FlameHasher : public Hasher {
|
||||
public:
|
||||
FlameHasher(QString file_path) : Hasher(file_path) { setObjectName(QString("FlameHasher: %1").arg(file_path)); }
|
||||
|
||||
void executeTask() override;
|
||||
};
|
||||
|
||||
class ModrinthHasher : public Hasher {
|
||||
public:
|
||||
ModrinthHasher(QString file_path) : Hasher(file_path) { setObjectName(QString("ModrinthHasher: %1").arg(file_path)); }
|
||||
|
||||
void executeTask() override;
|
||||
};
|
||||
|
||||
class BlockedModHasher : public Hasher {
|
||||
public:
|
||||
BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider);
|
||||
|
||||
void executeTask() override;
|
||||
|
||||
QStringList getHashTypes();
|
||||
bool useHashType(QString type);
|
||||
|
||||
private:
|
||||
ModPlatform::ResourceProvider provider;
|
||||
QString hash_type;
|
||||
Algorithm m_alg;
|
||||
};
|
||||
|
||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider);
|
||||
Hasher::Ptr createFlameHasher(QString file_path);
|
||||
Hasher::Ptr createModrinthHasher(QString file_path);
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider);
|
||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider, QString type);
|
||||
Hasher::Ptr createHasher(QString file_path, QString type);
|
||||
|
||||
} // namespace Hashing
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
static ModrinthAPI api;
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
bool ModrinthCheckUpdate::abort()
|
||||
{
|
||||
@ -36,7 +35,7 @@ void ModrinthCheckUpdate::executeTask()
|
||||
|
||||
// Create all hashes
|
||||
QStringList hashes;
|
||||
auto best_hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
auto best_hash_type = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||
|
||||
ConcurrentTask hashing_task(this, "MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
||||
for (auto* mod : m_mods) {
|
||||
@ -51,7 +50,7 @@ void ModrinthCheckUpdate::executeTask()
|
||||
// need to generate a new hash if the current one is innadequate
|
||||
// (though it will rarely happen, if at all)
|
||||
if (mod->metadata()->hash_format != best_hash_type) {
|
||||
auto hash_task = Hashing::createModrinthHasher(mod->fileinfo().absoluteFilePath());
|
||||
auto hash_task = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::MODRINTH);
|
||||
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [&hashes, &mappings, mod](QString hash) {
|
||||
hashes.append(hash);
|
||||
mappings.insert(hash, mod);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/mod/MetadataHandler.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "modplatform/helpers/HashUtils.h"
|
||||
|
||||
const QStringList ModrinthPackExportTask::PREFIXES({ "mods/", "coremods/", "resourcepacks/", "texturepacks/", "shaderpacks/" });
|
||||
const QStringList ModrinthPackExportTask::FILE_EXTENSIONS({ "jar", "litemod", "zip" });
|
||||
@ -102,8 +103,6 @@ void ModrinthPackExportTask::collectHashes()
|
||||
}))
|
||||
continue;
|
||||
|
||||
QCryptographicHash sha512(QCryptographicHash::Algorithm::Sha512);
|
||||
|
||||
QFile openFile(file.absoluteFilePath());
|
||||
if (!openFile.open(QFile::ReadOnly)) {
|
||||
qWarning() << "Could not open" << file << "for hashing";
|
||||
@ -115,7 +114,7 @@ void ModrinthPackExportTask::collectHashes()
|
||||
qWarning() << "Could not read" << file;
|
||||
continue;
|
||||
}
|
||||
sha512.addData(data);
|
||||
auto sha512 = Hashing::hash(data, Hashing::Algorithm::Sha512);
|
||||
|
||||
auto allMods = mcInstance->loaderModList()->allMods();
|
||||
if (auto modIter = std::find_if(allMods.begin(), allMods.end(), [&file](Mod* mod) { return mod->fileinfo() == file; });
|
||||
@ -127,11 +126,9 @@ void ModrinthPackExportTask::collectHashes()
|
||||
if (!url.isEmpty() && BuildConfig.MODRINTH_MRPACK_HOSTS.contains(url.host())) {
|
||||
qDebug() << "Resolving" << relative << "from index";
|
||||
|
||||
QCryptographicHash sha1(QCryptographicHash::Algorithm::Sha1);
|
||||
sha1.addData(data);
|
||||
auto sha1 = Hashing::hash(data, Hashing::Algorithm::Sha1);
|
||||
|
||||
ResolvedFile resolvedFile{ sha1.result().toHex(), sha512.result().toHex(), url.toEncoded(), openFile.size(),
|
||||
mod->metadata()->side };
|
||||
ResolvedFile resolvedFile{ sha1, sha512, url.toEncoded(), openFile.size(), mod->metadata()->side };
|
||||
resolvedFiles[relative] = resolvedFile;
|
||||
|
||||
// nice! we've managed to resolve based on local metadata!
|
||||
@ -142,7 +139,7 @@ void ModrinthPackExportTask::collectHashes()
|
||||
}
|
||||
|
||||
qDebug() << "Enqueueing" << relative << "for Modrinth query";
|
||||
pendingHashes[relative] = sha512.result().toHex();
|
||||
pendingHashes[relative] = sha512;
|
||||
}
|
||||
|
||||
setAbortable(true);
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
static ModrinthAPI api;
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
bool shouldDownloadOnSide(QString side)
|
||||
{
|
||||
@ -231,7 +230,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
||||
file.hash = Json::requireString(hash_list, preferred_hash_type);
|
||||
file.hash_type = preferred_hash_type;
|
||||
} else {
|
||||
auto hash_types = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH);
|
||||
auto hash_types = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH);
|
||||
for (auto& hash_type : hash_types) {
|
||||
if (hash_list.contains(hash_type)) {
|
||||
file.hash = Json::requireString(hash_list, hash_type);
|
||||
|
@ -67,8 +67,6 @@ static inline auto indexFileName(QString const& mod_slug) -> QString
|
||||
return QString("%1.pw.toml").arg(mod_slug);
|
||||
}
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
// Helper functions for extracting data from the TOML file
|
||||
auto stringEntry(toml::table table, QString entry_name) -> QString
|
||||
{
|
||||
@ -219,7 +217,7 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
||||
{ "hash-format", mod.hash_format.toStdString() },
|
||||
{ "hash", mod.hash.toStdString() },
|
||||
} },
|
||||
{ "update", toml::table{ { ProviderCaps.name(mod.provider), update } } } };
|
||||
{ "update", toml::table{ { ModPlatform::ProviderCapabilities::name(mod.provider), update } } } };
|
||||
std::stringstream ss;
|
||||
ss << tbl;
|
||||
in_stream << QString::fromStdString(ss.str());
|
||||
@ -340,11 +338,11 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod
|
||||
}
|
||||
|
||||
toml::table* mod_provider_table = nullptr;
|
||||
if ((mod_provider_table = update_table[ProviderCaps.name(Provider::FLAME)].as_table())) {
|
||||
if ((mod_provider_table = update_table[ModPlatform::ProviderCapabilities::name(Provider::FLAME)].as_table())) {
|
||||
mod.provider = Provider::FLAME;
|
||||
mod.file_id = intEntry(*mod_provider_table, "file-id");
|
||||
mod.project_id = intEntry(*mod_provider_table, "project-id");
|
||||
} else if ((mod_provider_table = update_table[ProviderCaps.name(Provider::MODRINTH)].as_table())) {
|
||||
} else if ((mod_provider_table = update_table[ModPlatform::ProviderCapabilities::name(Provider::MODRINTH)].as_table())) {
|
||||
mod.provider = Provider::MODRINTH;
|
||||
mod.mod_id() = stringEntry(*mod_provider_table, "mod-id");
|
||||
mod.version() = stringEntry(*mod_provider_table, "version");
|
||||
|
@ -266,7 +266,7 @@ void BlockedModsDialog::addHashTask(QString path)
|
||||
/// @param path the path to the local file being hashed
|
||||
void BlockedModsDialog::buildHashTask(QString path)
|
||||
{
|
||||
auto hash_task = Hashing::createBlockedModHasher(path, ModPlatform::ResourceProvider::FLAME, m_hash_type);
|
||||
auto hash_task = Hashing::createHasher(path, m_hash_type);
|
||||
|
||||
qDebug() << "[Blocked Mods Dialog] Creating Hash task for path: " << path;
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
ChooseProviderDialog::ChooseProviderDialog(QWidget* parent, bool single_choice, bool allow_skipping)
|
||||
: QDialog(parent), ui(new Ui::ChooseProviderDialog)
|
||||
{
|
||||
@ -78,7 +76,7 @@ void ChooseProviderDialog::addProviders()
|
||||
QRadioButton* btn;
|
||||
|
||||
for (auto& provider : { ModPlatform::ResourceProvider::MODRINTH, ModPlatform::ResourceProvider::FLAME }) {
|
||||
btn = new QRadioButton(ProviderCaps.readableName(provider), this);
|
||||
btn = new QRadioButton(ModPlatform::ProviderCapabilities::readableName(provider), this);
|
||||
m_providers.addButton(btn, btn_index++);
|
||||
ui->providersLayout->addWidget(btn);
|
||||
}
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
static std::list<Version> mcVersions(BaseInstance* inst)
|
||||
{
|
||||
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() };
|
||||
@ -427,7 +425,7 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info, QStri
|
||||
item_top->setExpanded(true);
|
||||
|
||||
auto provider_item = new QTreeWidgetItem(item_top);
|
||||
provider_item->setText(0, tr("Provider: %1").arg(ProviderCaps.readableName(info.provider)));
|
||||
provider_item->setText(0, tr("Provider: %1").arg(ModPlatform::ProviderCapabilities::readableName(info.provider)));
|
||||
|
||||
auto old_version_item = new QTreeWidgetItem(item_top);
|
||||
old_version_item->setText(0, tr("Old version: %1").arg(info.old_version.isEmpty() ? tr("Not installed") : info.old_version));
|
||||
|
@ -126,8 +126,6 @@ void ResourceDownloadDialog::connectButtons()
|
||||
connect(HelpButton, &QPushButton::clicked, m_container, &PageContainer::help);
|
||||
}
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
void ResourceDownloadDialog::confirm()
|
||||
{
|
||||
auto confirm_dialog = ReviewMessageBox::create(this, tr("Confirm %1 to download").arg(resourcesString()));
|
||||
@ -169,7 +167,7 @@ void ResourceDownloadDialog::confirm()
|
||||
for (auto& task : selected) {
|
||||
auto extraInfo = dependencyExtraInfo.value(task->getPack()->addonId.toString());
|
||||
confirm_dialog->appendResource({ task->getName(), task->getFilename(), task->getCustomPath(),
|
||||
ProviderCaps.name(task->getProvider()), extraInfo.required_by,
|
||||
ModPlatform::ProviderCapabilities::name(task->getProvider()), extraInfo.required_by,
|
||||
task->getVersion().version_type.toString(), !extraInfo.maybe_installed });
|
||||
}
|
||||
|
||||
|
@ -8,14 +8,14 @@
|
||||
|
||||
#include "MurmurHash2.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace Murmur2 {
|
||||
|
||||
// 'm' and 'r' are mixing constants generated offline.
|
||||
// They're not really 'magic', they just happen to work well.
|
||||
const uint32_t m = 0x5bd1e995;
|
||||
const int r = 24;
|
||||
|
||||
uint32_t MurmurHash2(std::ifstream&& file_stream, std::size_t buffer_size, std::function<bool(char)> filter_out)
|
||||
uint32_t hash(Reader* file_stream, std::size_t buffer_size, std::function<bool(char)> filter_out)
|
||||
{
|
||||
auto* buffer = new char[buffer_size];
|
||||
char data[4];
|
||||
@ -26,24 +26,21 @@ uint32_t MurmurHash2(std::ifstream&& file_stream, std::size_t buffer_size, std::
|
||||
// We need the size without the filtered out characters before actually calculating the hash,
|
||||
// to setup the initial value for the hash.
|
||||
do {
|
||||
file_stream.read(buffer, buffer_size);
|
||||
read = file_stream.gcount();
|
||||
read = file_stream->read(buffer, buffer_size);
|
||||
for (int i = 0; i < read; i++) {
|
||||
if (!filter_out(buffer[i]))
|
||||
size += 1;
|
||||
}
|
||||
} while (!file_stream.eof());
|
||||
} while (!file_stream->eof());
|
||||
|
||||
file_stream.clear();
|
||||
file_stream.seekg(0, file_stream.beg);
|
||||
file_stream->goToBegining();
|
||||
|
||||
int index = 0;
|
||||
|
||||
// This forces a seed of 1.
|
||||
IncrementalHashInfo info{ (uint32_t)1 ^ size, (uint32_t)size };
|
||||
do {
|
||||
file_stream.read(buffer, buffer_size);
|
||||
read = file_stream.gcount();
|
||||
read = file_stream->read(buffer, buffer_size);
|
||||
for (int i = 0; i < read; i++) {
|
||||
char c = buffer[i];
|
||||
|
||||
@ -57,14 +54,13 @@ uint32_t MurmurHash2(std::ifstream&& file_stream, std::size_t buffer_size, std::
|
||||
if (index == 0)
|
||||
FourBytes_MurmurHash2(reinterpret_cast<unsigned char*>(&data), info);
|
||||
}
|
||||
} while (!file_stream.eof());
|
||||
} while (!file_stream->eof());
|
||||
|
||||
// Do one last bit shuffle in the hash
|
||||
FourBytes_MurmurHash2(reinterpret_cast<unsigned char*>(&data), info);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
file_stream.close();
|
||||
return info.h;
|
||||
}
|
||||
|
||||
@ -109,4 +105,4 @@ void FourBytes_MurmurHash2(const unsigned char* data, IncrementalHashInfo& prev)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
} // namespace Murmur2
|
@ -9,17 +9,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
|
||||
#include <functional>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace Murmur2 {
|
||||
|
||||
#define KiB 1024
|
||||
#define MiB 1024 * KiB
|
||||
|
||||
uint32_t MurmurHash2(
|
||||
std::ifstream&& file_stream,
|
||||
class Reader {
|
||||
public:
|
||||
virtual ~Reader() = default;
|
||||
virtual int read(char* s, int n) = 0;
|
||||
virtual bool eof() = 0;
|
||||
virtual void goToBegining() = 0;
|
||||
};
|
||||
|
||||
uint32_t hash(
|
||||
Reader* file_stream,
|
||||
std::size_t buffer_size = 4 * MiB,
|
||||
std::function<bool(char)> filter_out = [](char) { return false; });
|
||||
|
||||
@ -29,5 +35,4 @@ struct IncrementalHashInfo {
|
||||
};
|
||||
|
||||
void FourBytes_MurmurHash2(const unsigned char* data, IncrementalHashInfo& prev);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
} // namespace Murmur2
|
||||
|
Loading…
Reference in New Issue
Block a user