From 8cfd8032227004c2abda92fa11f9e2218a807d9d Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Mon, 1 Mar 2021 10:41:31 +0300 Subject: [PATCH 1/2] Drop implicit conversions between InfoHash and QString --- src/app/application.cpp | 2 +- src/base/bittorrent/infohash.cpp | 40 ++++++++++--------- src/base/bittorrent/infohash.h | 7 ++-- src/base/bittorrent/magneturi.cpp | 4 +- src/base/bittorrent/session.cpp | 26 ++++++------ src/base/bittorrent/torrentimpl.cpp | 2 +- src/base/bittorrent/tracker.cpp | 2 +- src/gui/addnewtorrentdialog.cpp | 4 +- src/gui/properties/propertieswidget.cpp | 2 +- src/gui/transferlistwidget.cpp | 2 +- src/webui/api/serialize/serialize_torrent.cpp | 2 +- src/webui/api/synccontroller.cpp | 8 ++-- src/webui/api/torrentscontroller.cpp | 39 +++++++++--------- 13 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index eb7db1634..0ac15cb4f 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -339,7 +339,7 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const program.replace("%C", QString::number(torrent->filesCount())); program.replace("%Z", QString::number(torrent->totalSize())); program.replace("%T", torrent->currentTracker()); - program.replace("%I", torrent->hash()); + program.replace("%I", torrent->hash().toString()); Logger *logger = Logger::instance(); logger->addMessage(tr("Torrent: %1, running external program, command: %2").arg(torrent->name(), program)); diff --git a/src/base/bittorrent/infohash.cpp b/src/base/bittorrent/infohash.cpp index 3a2c0371c..f7ea61a8c 100644 --- a/src/base/bittorrent/infohash.cpp +++ b/src/base/bittorrent/infohash.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015 Vladimir Golovnev + * Copyright (C) 2015, 2021 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -36,28 +36,13 @@ using namespace BitTorrent; const int InfoHashTypeId = qRegisterMetaType(); InfoHash::InfoHash(const lt::sha1_hash &nativeHash) - : m_valid(true) - , m_nativeHash(nativeHash) + : m_valid {true} + , m_nativeHash {nativeHash} { const QByteArray raw = QByteArray::fromRawData(nativeHash.data(), length()); m_hashString = QString::fromLatin1(raw.toHex()); } -InfoHash::InfoHash(const QString &hashString) - : m_valid(false) -{ - if (hashString.size() != (length() * 2)) - return; - - const QByteArray raw = QByteArray::fromHex(hashString.toLatin1()); - if (raw.size() != length()) // QByteArray::fromHex() will skip over invalid characters - return; - - m_valid = true; - m_hashString = hashString; - m_nativeHash.assign(raw.constData()); -} - bool InfoHash::isValid() const { return m_valid; @@ -68,7 +53,24 @@ InfoHash::operator lt::sha1_hash() const return m_nativeHash; } -InfoHash::operator QString() const +InfoHash InfoHash::fromString(const QString &hashString) +{ + if (hashString.size() != (length() * 2)) + return {}; + + const QByteArray raw = QByteArray::fromHex(hashString.toLatin1()); + if (raw.size() != length()) // QByteArray::fromHex() will skip over invalid characters + return {}; + + InfoHash result; + result.m_valid = true; + result.m_hashString = hashString; + result.m_nativeHash.assign(raw.constData()); + + return result; +} + +QString InfoHash::toString() const { return m_hashString; } diff --git a/src/base/bittorrent/infohash.h b/src/base/bittorrent/infohash.h index 81c35f5dd..1e2ec3b7f 100644 --- a/src/base/bittorrent/infohash.h +++ b/src/base/bittorrent/infohash.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015 Vladimir Golovnev + * Copyright (C) 2015, 2021 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -40,7 +40,6 @@ namespace BitTorrent public: InfoHash() = default; InfoHash(const lt::sha1_hash &nativeHash); - InfoHash(const QString &hashString); InfoHash(const InfoHash &other) = default; static constexpr int length() @@ -51,7 +50,9 @@ namespace BitTorrent bool isValid() const; operator lt::sha1_hash() const; - operator QString() const; + + static InfoHash fromString(const QString &hashString); + QString toString() const; private: bool m_valid = false; diff --git a/src/base/bittorrent/magneturi.cpp b/src/base/bittorrent/magneturi.cpp index 4800cb41a..7bc44a242 100644 --- a/src/base/bittorrent/magneturi.cpp +++ b/src/base/bittorrent/magneturi.cpp @@ -40,7 +40,7 @@ namespace { - bool isBitTorrentInfoHash(const QString &string) + bool isSHA1Hash(const QString &string) { // There are 2 representations for BitTorrent info hash: // 1. 40 chars hex-encoded string @@ -65,7 +65,7 @@ MagnetUri::MagnetUri(const QString &source) { if (source.isEmpty()) return; - if (isBitTorrentInfoHash(source)) + if (isSHA1Hash(source)) m_url = QLatin1String("magnet:?xt=urn:btih:") + source; lt::error_code ec; diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index a6d0f6acc..dd13629ea 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -1802,7 +1802,7 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio TorrentImpl *const torrent = m_torrents.take(hash); if (!torrent) return false; - qDebug("Deleting torrent with hash: %s", qUtf8Printable(torrent->hash())); + qDebug("Deleting torrent with hash: %s", qUtf8Printable(torrent->hash().toString())); emit torrentAboutToBeRemoved(torrent); // Remove it from session @@ -1856,8 +1856,8 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio } // Remove it from torrent resume directory - const QString resumedataFile = QString::fromLatin1("%1.fastresume").arg(torrent->hash()); - const QString metadataFile = QString::fromLatin1("%1.torrent").arg(torrent->hash()); + const QString resumedataFile = QString::fromLatin1("%1.fastresume").arg(torrent->hash().toString()); + const QString metadataFile = QString::fromLatin1("%1.torrent").arg(torrent->hash().toString()); #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) QMetaObject::invokeMethod(m_resumeDataSavingManager, [this, resumedataFile, metadataFile]() { @@ -2254,7 +2254,7 @@ bool Session::downloadMetadata(const MagnetUri &magnetUri) if (m_downloadedMetadata.contains(hash)) return false; qDebug("Adding torrent to preload metadata..."); - qDebug(" -> Hash: %s", qUtf8Printable(hash)); + qDebug(" -> Hash: %s", qUtf8Printable(hash.toString())); qDebug(" -> Name: %s", qUtf8Printable(name)); lt::add_torrent_params p = magnetUri.addTorrentParams(); @@ -2270,7 +2270,7 @@ bool Session::downloadMetadata(const MagnetUri &magnetUri) p.max_connections = maxConnectionsPerTorrent(); p.max_uploads = maxUploadsPerTorrent(); - const QString savePath = Utils::Fs::tempPath() + static_cast(hash); + const QString savePath = Utils::Fs::tempPath() + hash.toString(); p.save_path = Utils::Fs::toNativePath(savePath).toStdString(); // Forced start @@ -2303,7 +2303,7 @@ void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder fold ((folder == TorrentExportFolder::Finished) && !finishedTorrentExportDirectory().isEmpty())); const QString validName = Utils::Fs::toValidFileSystemName(torrent->name()); - const QString torrentFilename = QString::fromLatin1("%1.torrent").arg(torrent->hash()); + const QString torrentFilename = QString::fromLatin1("%1.torrent").arg(torrent->hash().toString()); QString torrentExportFilename = QString::fromLatin1("%1.torrent").arg(validName); const QString torrentPath = QDir(m_resumeFolderPath).absoluteFilePath(torrentFilename); const QDir exportPath(folder == TorrentExportFolder::Regular ? torrentExportDirectory() : finishedTorrentExportDirectory()); @@ -2376,7 +2376,7 @@ void Session::saveTorrentsQueue() const // We require actual (non-cached) queue position here! const int queuePos = static_cast>(torrent->nativeHandle().queue_position()); if (queuePos >= 0) - queue[queuePos] = torrent->hash(); + queue[queuePos] = torrent->hash().toString(); } QByteArray data; @@ -3856,7 +3856,7 @@ void Session::handleTorrentMetadataReceived(TorrentImpl *const torrent) { // Save metadata const QDir resumeDataDir {m_resumeFolderPath}; - const QString torrentFileName {QString {"%1.torrent"}.arg(torrent->hash())}; + const QString torrentFileName {QString {"%1.torrent"}.arg(torrent->hash().toString())}; try { torrent->info().saveToFile(resumeDataDir.absoluteFilePath(torrentFileName)); @@ -3936,7 +3936,7 @@ void Session::handleTorrentResumeDataReady(TorrentImpl *const torrent, const std // Separated thread is used for the blocking IO which results in slow processing of many torrents. // Copying lt::entry objects around isn't cheap. - const QString filename = QString::fromLatin1("%1.fastresume").arg(torrent->hash()); + const QString filename = QString::fromLatin1("%1.fastresume").arg(torrent->hash().toString()); #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) QMetaObject::invokeMethod(m_resumeDataSavingManager , [this, filename, data]() { m_resumeDataSavingManager->save(filename, data); }); @@ -4014,7 +4014,7 @@ void Session::moveTorrentStorage(const MoveStorageJob &job) const { const InfoHash infoHash = job.torrentHandle.info_hash(); const TorrentImpl *torrent = m_torrents.value(infoHash); - const QString torrentName = (torrent ? torrent->name() : QString {infoHash}); + const QString torrentName = (torrent ? torrent->name() : infoHash.toString()); LogMsg(tr("Moving \"%1\" to \"%2\"...").arg(torrentName, job.path)); job.torrentHandle.move_storage(job.path.toUtf8().constData() @@ -4587,7 +4587,7 @@ void Session::createTorrent(const lt::torrent_handle &nativeHandle) { // Backup torrent file const QDir resumeDataDir {m_resumeFolderPath}; - const QString torrentFileName {QString {"%1.torrent"}.arg(torrent->hash())}; + const QString torrentFileName {QString::fromLatin1("%1.torrent").arg(torrent->hash().toString())}; try { torrent->info().saveToFile(resumeDataDir.absoluteFilePath(torrentFileName)); @@ -4925,7 +4925,7 @@ void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p) const InfoHash infoHash = currentJob.torrentHandle.info_hash(); TorrentImpl *torrent = m_torrents.value(infoHash); - const QString torrentName = (torrent ? torrent->name() : QString {infoHash}); + const QString torrentName = (torrent ? torrent->name() : infoHash.toString()); LogMsg(tr("\"%1\" is successfully moved to \"%2\".").arg(torrentName, newPath)); handleMoveTorrentStorageJobFinished(); @@ -4940,7 +4940,7 @@ void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert const InfoHash infoHash = currentJob.torrentHandle.info_hash(); TorrentImpl *torrent = m_torrents.value(infoHash); - const QString torrentName = (torrent ? torrent->name() : QString {infoHash}); + const QString torrentName = (torrent ? torrent->name() : infoHash.toString()); const QString currentLocation = QString::fromStdString(p->handle.status(lt::torrent_handle::query_save_path).save_path); const QString errorMessage = QString::fromStdString(p->message()); LogMsg(tr("Failed to move \"%1\" from \"%2\" to \"%3\". Reason: %4.") diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index dc86751b8..ed29b1f05 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -185,7 +185,7 @@ QString TorrentImpl::name() const if (!name.isEmpty()) return name; - return m_hash; + return m_hash.toString(); } QDateTime TorrentImpl::creationDate() const diff --git a/src/base/bittorrent/tracker.cpp b/src/base/bittorrent/tracker.cpp index 212d50616..f4cfeae43 100644 --- a/src/base/bittorrent/tracker.cpp +++ b/src/base/bittorrent/tracker.cpp @@ -295,7 +295,7 @@ void Tracker::processAnnounceRequest() if (infoHashIter == queryParams.end()) throw TrackerError("Missing \"info_hash\" parameter"); - const InfoHash infoHash(infoHashIter->toHex()); + const auto infoHash = InfoHash::fromString(infoHashIter->toHex()); if (!infoHash.isValid()) throw TrackerError("Invalid \"info_hash\" parameter"); diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index a90c227da..f98361577 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -296,7 +296,7 @@ bool AddNewTorrentDialog::loadTorrentImpl() return false; } - m_ui->labelHashData->setText(infoHash); + m_ui->labelHashData->setText(infoHash.toString()); setupTreeview(); TMMChanged(m_ui->comboTTM->currentIndex()); return true; @@ -348,7 +348,7 @@ bool AddNewTorrentDialog::loadMagnet(const BitTorrent::MagnetUri &magnetUri) BitTorrent::Session::instance()->downloadMetadata(magnetUri); setMetadataProgressIndicator(true, tr("Retrieving metadata...")); - m_ui->labelHashData->setText(infoHash); + m_ui->labelHashData->setText(infoHash.toString()); m_magnetURI = magnetUri; return true; diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index cdb68da86..b74e4312c 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -313,7 +313,7 @@ void PropertiesWidget::loadTorrentInfos(BitTorrent::Torrent *const torrent) // Save path updateSavePath(m_torrent); // Hash - m_ui->labelHashVal->setText(m_torrent->hash()); + m_ui->labelHashVal->setText(m_torrent->hash().toString()); m_propListModel->model()->clear(); if (m_torrent->hasMetadata()) { diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index c5662fb44..df1d3b638 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -496,7 +496,7 @@ void TransferListWidget::copySelectedHashes() const { QStringList torrentHashes; for (BitTorrent::Torrent *const torrent : asConst(getSelectedTorrents())) - torrentHashes << torrent->hash(); + torrentHashes << torrent->hash().toString(); qApp->clipboard()->setText(torrentHashes.join('\n')); } diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index 9b987f7bd..d39115091 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -103,7 +103,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent) }; return { - {KEY_TORRENT_HASH, QString(torrent.hash())}, + {KEY_TORRENT_HASH, QString(torrent.hash().toString())}, {KEY_TORRENT_NAME, torrent.name()}, {KEY_TORRENT_MAGNET_URI, torrent.createMagnetURI()}, {KEY_TORRENT_SIZE, torrent.wantedSize()}, diff --git a/src/webui/api/synccontroller.cpp b/src/webui/api/synccontroller.cpp index b8c24b39c..55df82a38 100644 --- a/src/webui/api/synccontroller.cpp +++ b/src/webui/api/synccontroller.cpp @@ -471,7 +471,7 @@ void SyncController::maindataAction() if (iterTorrents != lastResponse.end()) { const QVariantHash lastResponseTorrents = iterTorrents->toHash(); - const auto iterHash = lastResponseTorrents.find(torrentHash); + const auto iterHash = lastResponseTorrents.find(torrentHash.toString()); if (iterHash != lastResponseTorrents.end()) { @@ -488,9 +488,9 @@ void SyncController::maindataAction() } for (const BitTorrent::TrackerEntry &tracker : asConst(torrent->trackers())) - trackers[tracker.url()] << torrentHash; + trackers[tracker.url()] << torrentHash.toString(); - torrents[torrentHash] = map; + torrents[torrentHash.toString()] = map; } data["torrents"] = torrents; @@ -541,7 +541,7 @@ void SyncController::torrentPeersAction() auto lastResponse = sessionManager()->session()->getData(QLatin1String("syncTorrentPeersLastResponse")).toMap(); auto lastAcceptedResponse = sessionManager()->session()->getData(QLatin1String("syncTorrentPeersLastAcceptedResponse")).toMap(); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); const BitTorrent::Torrent *torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index e8149dd5b..b06dd7654 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -127,8 +127,9 @@ namespace } else { - for (const QString &hash : hashes) + for (const QString &hashString : hashes) { + const auto hash = BitTorrent::InfoHash::fromString(hashString); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (torrent) func(torrent); @@ -213,7 +214,7 @@ namespace QVector infoHashes; infoHashes.reserve(hashes.size()); for (const QString &hash : hashes) - infoHashes << hash; + infoHashes << BitTorrent::InfoHash::fromString(hash); return infoHashes; } } @@ -259,7 +260,7 @@ void TorrentsController::infoAction() InfoHashSet hashSet; for (const QString &hash : hashes) - hashSet.insert(BitTorrent::InfoHash {hash}); + hashSet.insert(BitTorrent::InfoHash::fromString(hash)); const TorrentFilter torrentFilter(filter, (hashes.isEmpty() ? TorrentFilter::AnyHash : hashSet), category); QVariantList torrentList; @@ -371,7 +372,7 @@ void TorrentsController::propertiesAction() { requireParams({"hash"}); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -442,7 +443,7 @@ void TorrentsController::trackersAction() { requireParams({"hash"}); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); const BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -478,7 +479,7 @@ void TorrentsController::webseedsAction() { requireParams({"hash"}); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -509,7 +510,7 @@ void TorrentsController::filesAction() { requireParams({"hash"}); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); const BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -555,7 +556,7 @@ void TorrentsController::pieceHashesAction() { requireParams({"hash"}); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -577,7 +578,7 @@ void TorrentsController::pieceStatesAction() { requireParams({"hash"}); - const QString hash {params()["hash"]}; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -683,7 +684,7 @@ void TorrentsController::addTrackersAction() { requireParams({"hash", "urls"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -702,7 +703,7 @@ void TorrentsController::editTrackerAction() { requireParams({"hash", "origUrl", "newUrl"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); const QString origUrl = params()["origUrl"]; const QString newUrl = params()["newUrl"]; @@ -745,7 +746,7 @@ void TorrentsController::removeTrackersAction() { requireParams({"hash", "urls"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -798,7 +799,7 @@ void TorrentsController::addPeersAction() return torrent->connectPeer(peer); }); - results[torrent->hash()] = QJsonObject + results[torrent->hash().toString()] = QJsonObject { {"added", peersAdded}, {"failed", (peers.size() - peersAdded)} @@ -828,7 +829,7 @@ void TorrentsController::filePrioAction() { requireParams({"hash", "id", "priority"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); bool ok = false; const auto priority = static_cast(params()["priority"].toInt(&ok)); if (!ok) @@ -874,7 +875,7 @@ void TorrentsController::uploadLimitAction() for (const QString &hash : hashes) { int limit = -1; - const BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); + const BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(BitTorrent::InfoHash::fromString(hash)); if (torrent) limit = torrent->uploadLimit(); map[hash] = limit; @@ -892,7 +893,7 @@ void TorrentsController::downloadLimitAction() for (const QString &hash : hashes) { int limit = -1; - const BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); + const BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(BitTorrent::InfoHash::fromString(hash)); if (torrent) limit = torrent->downloadLimit(); map[hash] = limit; @@ -1064,7 +1065,7 @@ void TorrentsController::renameAction() { requireParams({"hash", "name"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); QString name = params()["name"].trimmed(); if (name.isEmpty()) @@ -1251,7 +1252,7 @@ void TorrentsController::renameFileAction() { requireParams({"hash", "oldPath", "newPath"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); @@ -1273,7 +1274,7 @@ void TorrentsController::renameFolderAction() { requireParams({"hash", "oldPath", "newPath"}); - const QString hash = params()["hash"]; + const auto hash = BitTorrent::InfoHash::fromString(params()["hash"]); BitTorrent::Torrent *const torrent = BitTorrent::Session::instance()->findTorrent(hash); if (!torrent) throw APIError(APIErrorType::NotFound); From bea32cfe38be7a232222937a5b4db2493d53a0ad Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Tue, 2 Mar 2021 19:44:57 +0300 Subject: [PATCH 2/2] Define template for classes that represent SHA hashes --- src/base/CMakeLists.txt | 1 + src/base/base.pri | 1 + src/base/bittorrent/infohash.cpp | 66 ++--------------- src/base/bittorrent/infohash.h | 35 +++------ src/base/digest32.h | 121 +++++++++++++++++++++++++++++++ src/gui/transferlistsortmodel.h | 1 + 6 files changed, 138 insertions(+), 87 deletions(-) create mode 100644 src/base/digest32.h diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index b5c48acc9..482e3c31e 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(qbt_base STATIC bittorrent/torrentinfo.h bittorrent/tracker.h bittorrent/trackerentry.h + digest32.h exceptions.h filesystemwatcher.h global.h diff --git a/src/base/base.pri b/src/base/base.pri index a9f6cbe65..95cf69246 100644 --- a/src/base/base.pri +++ b/src/base/base.pri @@ -31,6 +31,7 @@ HEADERS += \ $$PWD/bittorrent/torrentinfo.h \ $$PWD/bittorrent/tracker.h \ $$PWD/bittorrent/trackerentry.h \ + $$PWD/digest32.h \ $$PWD/exceptions.h \ $$PWD/filesystemwatcher.h \ $$PWD/global.h \ diff --git a/src/base/bittorrent/infohash.cpp b/src/base/bittorrent/infohash.cpp index f7ea61a8c..d46116e48 100644 --- a/src/base/bittorrent/infohash.cpp +++ b/src/base/bittorrent/infohash.cpp @@ -28,70 +28,14 @@ #include "infohash.h" -#include -#include +const int InfoHashTypeId = qRegisterMetaType(); -using namespace BitTorrent; - -const int InfoHashTypeId = qRegisterMetaType(); - -InfoHash::InfoHash(const lt::sha1_hash &nativeHash) - : m_valid {true} - , m_nativeHash {nativeHash} -{ - const QByteArray raw = QByteArray::fromRawData(nativeHash.data(), length()); - m_hashString = QString::fromLatin1(raw.toHex()); -} - -bool InfoHash::isValid() const -{ - return m_valid; -} - -InfoHash::operator lt::sha1_hash() const -{ - return m_nativeHash; -} - -InfoHash InfoHash::fromString(const QString &hashString) -{ - if (hashString.size() != (length() * 2)) - return {}; - - const QByteArray raw = QByteArray::fromHex(hashString.toLatin1()); - if (raw.size() != length()) // QByteArray::fromHex() will skip over invalid characters - return {}; - - InfoHash result; - result.m_valid = true; - result.m_hashString = hashString; - result.m_nativeHash.assign(raw.constData()); - - return result; -} - -QString InfoHash::toString() const -{ - return m_hashString; -} - -bool BitTorrent::operator==(const InfoHash &left, const InfoHash &right) -{ - return (static_cast(left) - == static_cast(right)); -} - -bool BitTorrent::operator!=(const InfoHash &left, const InfoHash &right) -{ - return !(left == right); -} - -bool BitTorrent::operator<(const InfoHash &left, const InfoHash &right) +BitTorrent::InfoHash BitTorrent::InfoHash::fromString(const QString &hashString) { - return static_cast(left) < static_cast(right); + return {SHA1Hash::fromString(hashString)}; } -uint BitTorrent::qHash(const InfoHash &key, const uint seed) +uint BitTorrent::qHash(const BitTorrent::InfoHash &key, const uint seed) { - return ::qHash((std::hash {})(key), seed); + return ::qHash(std::hash()(key), seed); } diff --git a/src/base/bittorrent/infohash.h b/src/base/bittorrent/infohash.h index 1e2ec3b7f..d6a4c874c 100644 --- a/src/base/bittorrent/infohash.h +++ b/src/base/bittorrent/infohash.h @@ -28,42 +28,25 @@ #pragma once -#include - +#include #include -#include + +#include "base/digest32.h" + +using SHA1Hash = Digest32<160>; +using SHA256Hash = Digest32<256>; namespace BitTorrent { - class InfoHash + class InfoHash : public SHA1Hash { public: - InfoHash() = default; - InfoHash(const lt::sha1_hash &nativeHash); - InfoHash(const InfoHash &other) = default; - - static constexpr int length() - { - return lt::sha1_hash::size(); - } - - bool isValid() const; - - operator lt::sha1_hash() const; + using SHA1Hash::SHA1Hash; static InfoHash fromString(const QString &hashString); - QString toString() const; - - private: - bool m_valid = false; - lt::sha1_hash m_nativeHash; - QString m_hashString; }; - bool operator==(const InfoHash &left, const InfoHash &right); - bool operator!=(const InfoHash &left, const InfoHash &right); - bool operator<(const InfoHash &left, const InfoHash &right); - uint qHash(const InfoHash &key, uint seed); + uint qHash(const InfoHash &key, const uint seed); } Q_DECLARE_METATYPE(BitTorrent::InfoHash) diff --git a/src/base/digest32.h b/src/base/digest32.h new file mode 100644 index 000000000..ece84af41 --- /dev/null +++ b/src/base/digest32.h @@ -0,0 +1,121 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015, 2021 Vladimir Golovnev + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +#include + +#include +#include +#include + +template +class Digest32 +{ +public: + using UnderlyingType = lt::digest32; + + Digest32() = default; + Digest32(const Digest32 &other) = default; + + Digest32(const UnderlyingType &nativeDigest) + : m_valid {true} + , m_nativeDigest {nativeDigest} + { + const QByteArray raw = QByteArray::fromRawData(nativeDigest.data(), length()); + m_hashString = QString::fromLatin1(raw.toHex()); + } + + static constexpr int length() + { + return UnderlyingType::size(); + } + + bool isValid() const + { + return m_valid; + } + + operator UnderlyingType() const + { + return m_nativeDigest; + } + + static Digest32 fromString(const QString &digestString) + { + if (digestString.size() != (length() * 2)) + return {}; + + const QByteArray raw = QByteArray::fromHex(digestString.toLatin1()); + if (raw.size() != length()) // QByteArray::fromHex() will skip over invalid characters + return {}; + + Digest32 result; + result.m_valid = true; + result.m_hashString = digestString; + result.m_nativeDigest.assign(raw.constData()); + + return result; + } + + QString toString() const + { + return m_hashString; + } + +private: + bool m_valid = false; + UnderlyingType m_nativeDigest; + QString m_hashString; +}; + +template +bool operator==(const Digest32 &left, const Digest32 &right) +{ + return (static_cast::UnderlyingType>(left) + == static_cast::UnderlyingType>(right)); +} + +template +bool operator!=(const Digest32 &left, const Digest32 &right) +{ + return !(left == right); +} + +template +bool operator<(const Digest32 &left, const Digest32 &right) +{ + return static_cast::UnderlyingType>(left) + < static_cast::UnderlyingType>(right); +} + +template +uint qHash(const Digest32 &key, const uint seed) +{ + return ::qHash(std::hash::UnderlyingType>()(key), seed); +} diff --git a/src/gui/transferlistsortmodel.h b/src/gui/transferlistsortmodel.h index 95df8426a..a8ea23dac 100644 --- a/src/gui/transferlistsortmodel.h +++ b/src/gui/transferlistsortmodel.h @@ -29,6 +29,7 @@ #pragma once #include + #include "base/torrentfilter.h" namespace BitTorrent