2019-03-21 22:04:56 +00:00
|
|
|
// Copyright 2019 Dolphin Emulator Project
|
2021-07-05 01:22:19 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2019-03-21 22:04:56 +00:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2019-08-06 09:39:09 +00:00
|
|
|
#include <future>
|
2019-03-26 16:22:18 +00:00
|
|
|
#include <map>
|
|
|
|
#include <optional>
|
2019-03-21 22:04:56 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2019-03-30 11:45:00 +00:00
|
|
|
#include <mbedtls/md5.h>
|
|
|
|
#include <mbedtls/sha1.h>
|
|
|
|
|
2019-03-21 22:04:56 +00:00
|
|
|
#include "Common/CommonTypes.h"
|
2019-07-14 13:01:07 +00:00
|
|
|
#include "Core/IOS/ES/Formats.h"
|
2019-03-30 15:20:45 +00:00
|
|
|
#include "DiscIO/DiscScrubber.h"
|
2019-03-21 22:04:56 +00:00
|
|
|
#include "DiscIO/Volume.h"
|
|
|
|
|
|
|
|
// To be used as follows:
|
|
|
|
//
|
2019-08-23 11:20:09 +00:00
|
|
|
// VolumeVerifier verifier(volume, redump_verification, hashes_to_calculate);
|
2019-03-21 22:04:56 +00:00
|
|
|
// verifier.Start();
|
|
|
|
// while (verifier.GetBytesProcessed() != verifier.GetTotalBytes())
|
|
|
|
// verifier.Process();
|
|
|
|
// verifier.Finish();
|
|
|
|
// auto result = verifier.GetResult();
|
|
|
|
//
|
|
|
|
// Start, Process and Finish may take some time to run.
|
|
|
|
//
|
|
|
|
// GetResult() can be called before the processing is finished, but the result will be incomplete.
|
|
|
|
|
|
|
|
namespace DiscIO
|
|
|
|
{
|
2019-08-23 11:20:09 +00:00
|
|
|
template <typename T>
|
|
|
|
struct Hashes
|
|
|
|
{
|
|
|
|
T crc32;
|
|
|
|
T md5;
|
|
|
|
T sha1;
|
|
|
|
};
|
|
|
|
|
|
|
|
class RedumpVerifier final
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum class Status
|
|
|
|
{
|
|
|
|
Unknown,
|
|
|
|
GoodDump,
|
|
|
|
BadDump,
|
|
|
|
Error,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Result
|
|
|
|
{
|
|
|
|
Status status = Status::Unknown;
|
|
|
|
std::string message;
|
|
|
|
};
|
|
|
|
|
|
|
|
void Start(const Volume& volume);
|
|
|
|
Result Finish(const Hashes<std::vector<u8>>& hashes);
|
|
|
|
|
|
|
|
private:
|
2019-08-24 10:53:13 +00:00
|
|
|
enum class DownloadStatus
|
|
|
|
{
|
|
|
|
NotAttempted,
|
|
|
|
Success,
|
|
|
|
Fail,
|
|
|
|
FailButOldCacheAvailable,
|
|
|
|
SystemNotAvailable,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DownloadState
|
|
|
|
{
|
|
|
|
std::mutex mutex;
|
|
|
|
DownloadStatus status = DownloadStatus::NotAttempted;
|
|
|
|
};
|
|
|
|
|
2019-08-23 11:20:09 +00:00
|
|
|
struct PotentialMatch
|
|
|
|
{
|
2021-09-04 04:43:19 +00:00
|
|
|
u64 size = 0;
|
2019-08-23 11:20:09 +00:00
|
|
|
Hashes<std::vector<u8>> hashes;
|
|
|
|
};
|
|
|
|
|
2019-08-24 10:53:13 +00:00
|
|
|
static DownloadStatus DownloadDatfile(const std::string& system, DownloadStatus old_status);
|
|
|
|
static std::vector<u8> ReadDatfile(const std::string& system);
|
2019-11-02 15:47:08 +00:00
|
|
|
std::vector<PotentialMatch> ScanDatfile(const std::vector<u8>& data, const std::string& system);
|
2019-08-23 11:20:09 +00:00
|
|
|
|
|
|
|
std::string m_game_id;
|
2021-09-04 04:43:19 +00:00
|
|
|
u16 m_revision = 0;
|
|
|
|
u8 m_disc_number = 0;
|
|
|
|
u64 m_size = 0;
|
2019-08-23 11:20:09 +00:00
|
|
|
|
|
|
|
std::future<std::vector<PotentialMatch>> m_future;
|
|
|
|
Result m_result;
|
2019-08-24 10:53:13 +00:00
|
|
|
|
|
|
|
static DownloadState m_gc_download_state;
|
|
|
|
static DownloadState m_wii_download_state;
|
2019-08-23 11:20:09 +00:00
|
|
|
};
|
|
|
|
|
2019-03-21 22:04:56 +00:00
|
|
|
class VolumeVerifier final
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum class Severity
|
|
|
|
{
|
|
|
|
None, // Only used internally
|
|
|
|
Low,
|
|
|
|
Medium,
|
|
|
|
High,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Problem
|
|
|
|
{
|
|
|
|
Severity severity;
|
|
|
|
std::string text;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Result
|
|
|
|
{
|
2019-03-30 11:45:00 +00:00
|
|
|
Hashes<std::vector<u8>> hashes;
|
2019-03-21 22:04:56 +00:00
|
|
|
std::string summary_text;
|
|
|
|
std::vector<Problem> problems;
|
2019-08-23 11:20:09 +00:00
|
|
|
RedumpVerifier::Result redump;
|
2019-03-21 22:04:56 +00:00
|
|
|
};
|
|
|
|
|
2019-08-23 11:20:09 +00:00
|
|
|
VolumeVerifier(const Volume& volume, bool redump_verification, Hashes<bool> hashes_to_calculate);
|
2019-05-27 14:19:49 +00:00
|
|
|
~VolumeVerifier();
|
|
|
|
|
2019-03-21 22:04:56 +00:00
|
|
|
void Start();
|
|
|
|
void Process();
|
|
|
|
u64 GetBytesProcessed() const;
|
|
|
|
u64 GetTotalBytes() const;
|
|
|
|
void Finish();
|
|
|
|
const Result& GetResult() const;
|
|
|
|
|
|
|
|
private:
|
2021-03-07 12:48:51 +00:00
|
|
|
struct GroupToVerify
|
2019-03-26 16:22:18 +00:00
|
|
|
{
|
|
|
|
Partition partition;
|
|
|
|
u64 offset;
|
2021-03-07 12:48:51 +00:00
|
|
|
size_t block_index_start;
|
|
|
|
size_t block_index_end;
|
2019-03-26 16:22:18 +00:00
|
|
|
};
|
|
|
|
|
2020-02-09 18:05:44 +00:00
|
|
|
std::vector<Partition> CheckPartitions();
|
2019-03-21 22:04:56 +00:00
|
|
|
bool CheckPartition(const Partition& partition); // Returns false if partition should be ignored
|
2019-03-26 16:22:18 +00:00
|
|
|
std::string GetPartitionName(std::optional<u32> type) const;
|
2019-03-21 22:04:56 +00:00
|
|
|
bool IsDebugSigned() const;
|
|
|
|
bool ShouldHaveChannelPartition() const;
|
|
|
|
bool ShouldHaveInstallPartition() const;
|
|
|
|
bool ShouldHaveMasterpiecePartitions() const;
|
|
|
|
bool ShouldBeDualLayer() const;
|
2020-09-23 08:29:04 +00:00
|
|
|
void CheckVolumeSize();
|
2019-03-21 22:04:56 +00:00
|
|
|
void CheckMisc();
|
2019-11-27 13:35:25 +00:00
|
|
|
void CheckSuperPaperMario();
|
2019-03-30 11:45:00 +00:00
|
|
|
void SetUpHashing();
|
2019-08-06 09:39:09 +00:00
|
|
|
void WaitForAsyncOperations() const;
|
|
|
|
bool ReadChunkAndWaitForAsyncOperations(u64 bytes_to_read);
|
2019-03-21 22:04:56 +00:00
|
|
|
|
2019-05-27 14:12:20 +00:00
|
|
|
void AddProblem(Severity severity, std::string text);
|
2019-03-21 22:04:56 +00:00
|
|
|
|
|
|
|
const Volume& m_volume;
|
|
|
|
Result m_result;
|
2019-05-27 14:23:52 +00:00
|
|
|
bool m_is_tgc = false;
|
|
|
|
bool m_is_datel = false;
|
|
|
|
bool m_is_not_retail = false;
|
2019-03-21 22:04:56 +00:00
|
|
|
|
2019-08-23 11:20:09 +00:00
|
|
|
bool m_redump_verification;
|
|
|
|
RedumpVerifier m_redump_verifier;
|
|
|
|
|
2020-01-25 18:41:58 +00:00
|
|
|
bool m_read_errors_occurred = false;
|
|
|
|
|
2019-05-27 14:23:52 +00:00
|
|
|
Hashes<bool> m_hashes_to_calculate{};
|
|
|
|
bool m_calculating_any_hash = false;
|
2021-12-10 21:34:40 +00:00
|
|
|
u32 m_crc32_context = 0;
|
2021-09-04 04:43:19 +00:00
|
|
|
mbedtls_md5_context m_md5_context{};
|
|
|
|
mbedtls_sha1_context m_sha1_context{};
|
2019-03-30 11:45:00 +00:00
|
|
|
|
2019-08-06 19:14:33 +00:00
|
|
|
u64 m_excess_bytes = 0;
|
2019-08-06 09:39:09 +00:00
|
|
|
std::vector<u8> m_data;
|
|
|
|
std::future<void> m_crc32_future;
|
|
|
|
std::future<void> m_md5_future;
|
|
|
|
std::future<void> m_sha1_future;
|
|
|
|
std::future<void> m_content_future;
|
2021-03-07 12:48:51 +00:00
|
|
|
std::future<void> m_group_future;
|
2019-08-06 09:39:09 +00:00
|
|
|
|
2019-03-30 15:20:45 +00:00
|
|
|
DiscScrubber m_scrubber;
|
2019-07-14 13:01:07 +00:00
|
|
|
IOS::ES::TicketReader m_ticket;
|
2019-03-30 16:42:31 +00:00
|
|
|
std::vector<u64> m_content_offsets;
|
|
|
|
u16 m_content_index = 0;
|
2021-03-07 12:48:51 +00:00
|
|
|
std::vector<GroupToVerify> m_groups;
|
|
|
|
size_t m_group_index = 0; // Index in m_groups, not index in a specific partition
|
2019-03-26 16:22:18 +00:00
|
|
|
std::map<Partition, size_t> m_block_errors;
|
2019-03-30 15:20:45 +00:00
|
|
|
std::map<Partition, size_t> m_unused_block_errors;
|
2019-03-26 16:22:18 +00:00
|
|
|
|
2019-06-18 13:37:10 +00:00
|
|
|
u64 m_biggest_referenced_offset = 0;
|
|
|
|
u64 m_biggest_verified_offset = 0;
|
|
|
|
|
2019-05-27 14:23:52 +00:00
|
|
|
bool m_started = false;
|
|
|
|
bool m_done = false;
|
|
|
|
u64 m_progress = 0;
|
|
|
|
u64 m_max_progress = 0;
|
2019-03-21 22:04:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace DiscIO
|