// Copyright 2019 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include #include "Common/CommonTypes.h" #include "Core/IOS/ES/Formats.h" #include "DiscIO/DiscScrubber.h" #include "DiscIO/Volume.h" // To be used as follows: // // VolumeVerifier verifier(volume, redump_verification, hashes_to_calculate); // 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 { template 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>& hashes); private: enum class DownloadStatus { NotAttempted, Success, Fail, FailButOldCacheAvailable, SystemNotAvailable, }; struct DownloadState { std::mutex mutex; DownloadStatus status = DownloadStatus::NotAttempted; }; struct PotentialMatch { u64 size = 0; Hashes> hashes; }; static DownloadStatus DownloadDatfile(const std::string& system, DownloadStatus old_status); static std::vector ReadDatfile(const std::string& system); std::vector ScanDatfile(const std::vector& data, const std::string& system); std::string m_game_id; u16 m_revision = 0; u8 m_disc_number = 0; u64 m_size = 0; std::future> m_future; Result m_result; static DownloadState m_gc_download_state; static DownloadState m_wii_download_state; }; class VolumeVerifier final { public: enum class Severity { None, // Only used internally Low, Medium, High, }; struct Problem { Severity severity; std::string text; }; struct Result { Hashes> hashes; std::string summary_text; std::vector problems; RedumpVerifier::Result redump; }; VolumeVerifier(const Volume& volume, bool redump_verification, Hashes hashes_to_calculate); ~VolumeVerifier(); void Start(); void Process(); u64 GetBytesProcessed() const; u64 GetTotalBytes() const; void Finish(); const Result& GetResult() const; private: struct GroupToVerify { Partition partition; u64 offset; size_t block_index_start; size_t block_index_end; }; std::vector CheckPartitions(); bool CheckPartition(const Partition& partition); // Returns false if partition should be ignored std::string GetPartitionName(std::optional type) const; bool IsDebugSigned() const; bool ShouldHaveChannelPartition() const; bool ShouldHaveInstallPartition() const; bool ShouldHaveMasterpiecePartitions() const; bool ShouldBeDualLayer() const; void CheckVolumeSize(); void CheckMisc(); void CheckSuperPaperMario(); void SetUpHashing(); void WaitForAsyncOperations() const; bool ReadChunkAndWaitForAsyncOperations(u64 bytes_to_read); void AddProblem(Severity severity, std::string text); const Volume& m_volume; Result m_result; bool m_is_tgc = false; bool m_is_datel = false; bool m_is_not_retail = false; bool m_redump_verification; RedumpVerifier m_redump_verifier; bool m_read_errors_occurred = false; Hashes m_hashes_to_calculate{}; bool m_calculating_any_hash = false; unsigned long m_crc32_context = 0; mbedtls_md5_context m_md5_context{}; mbedtls_sha1_context m_sha1_context{}; u64 m_excess_bytes = 0; std::vector m_data; std::future m_crc32_future; std::future m_md5_future; std::future m_sha1_future; std::future m_content_future; std::future m_group_future; DiscScrubber m_scrubber; IOS::ES::TicketReader m_ticket; std::vector m_content_offsets; u16 m_content_index = 0; std::vector m_groups; size_t m_group_index = 0; // Index in m_groups, not index in a specific partition std::map m_block_errors; std::map m_unused_block_errors; u64 m_biggest_referenced_offset = 0; u64 m_biggest_verified_offset = 0; bool m_started = false; bool m_done = false; u64 m_progress = 0; u64 m_max_progress = 0; }; } // namespace DiscIO