CDVD: Add IsoHasher

This commit is contained in:
Stenzek 2022-09-27 22:56:46 +10:00 committed by refractionpcsx2
parent eb8d938c94
commit 94c48a4c2d
5 changed files with 277 additions and 5 deletions

200
pcsx2/CDVD/IsoHasher.cpp Normal file
View File

@ -0,0 +1,200 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "CDVD/CDVDcommon.h"
#include "CDVD/IsoHasher.h"
#include "Host.h"
#include "common/Error.h"
#include "common/MD5Digest.h"
#include "common/StringUtil.h"
#include "fmt/core.h"
#include <algorithm>
IsoHasher::IsoHasher() = default;
IsoHasher::~IsoHasher()
{
Close();
}
std::string_view IsoHasher::GetTrackTypeString(u32 type)
{
switch (type)
{
case CDVD_AUDIO_TRACK:
return TRANSLATE_SV("CDVD", "Audio");
case CDVD_MODE1_TRACK:
return TRANSLATE_SV("CDVD", "Mode 1");
case CDVD_MODE2_TRACK:
return TRANSLATE_SV("CDVD", "Mode 2");
default:
return TRANSLATE_SV("CDVD", "Unknown");
}
}
bool IsoHasher::Open(std::string iso_path, Error* error)
{
Close();
CDVDsys_SetFile(CDVD_SourceType::Iso, std::move(iso_path));
CDVDsys_ChangeSource(CDVD_SourceType::Iso);
m_is_open = DoCDVDopen();
if (!m_is_open)
{
Error::SetString(error, "Failed to open CDVD.");
return false;
}
const s32 type = DoCDVDdetectDiskType();
switch (type)
{
case CDVD_TYPE_PSCD:
case CDVD_TYPE_PSCDDA:
case CDVD_TYPE_PS2CD:
case CDVD_TYPE_PS2CDDA:
m_is_cd = true;
break;
case CDVD_TYPE_PS2DVD:
m_is_cd = false;
break;
default:
Error::SetString(error, fmt::format("Unknown CDVD disk type {}", type));
return false;
}
cdvdTN tn;
if (CDVD->getTN(&tn) < 0)
{
Error::SetString(error, "Failed to get track count.");
return false;
}
for (u8 track = tn.strack; track <= tn.etrack; track++)
{
cdvdTD td, next_td;
if (CDVD->getTD(track, &td) < 0 || CDVD->getTD((track == tn.etrack) ? 0 : (track + 1), &next_td) < 0)
{
Error::SetString(error, fmt::format("Failed to get track range for {}", static_cast<unsigned>(track)));
return false;
}
// sanity check..
if (next_td.lsn < td.lsn)
{
Error::SetString(error,
fmt::format("Invalid track range for {} ({},{})", static_cast<unsigned>(track), td.lsn, next_td.lsn));
return false;
}
Track strack;
strack.number = track;
strack.type = td.type;
strack.start_lsn = td.lsn;
strack.sectors = next_td.lsn - td.lsn;
strack.size = static_cast<u64>(strack.sectors) * (m_is_cd ? 2352 : 2048);
m_tracks.push_back(std::move(strack));
}
return true;
}
void IsoHasher::Close()
{
if (!m_is_open)
return;
DoCDVDclose();
m_tracks.clear();
m_is_cd = false;
m_is_open = false;
}
void IsoHasher::ComputeHashes(ProgressCallback* callback)
{
callback->SetProgressRange(GetTrackCount());
callback->SetProgressValue(0);
callback->SetCancellable(true);
for (u32 index = 0; index < GetTrackCount(); index++)
{
Track& track = m_tracks[index];
if (!track.hash.empty())
{
callback->SetProgressValue(index + 1);
continue;
}
callback->PushState();
const bool result = ComputeTrackHash(track, callback);
callback->PopState();
if (!result)
break;
callback->SetProgressValue(index + 1);
callback->IncrementProgressValue();
}
callback->SetProgressValue(GetTrackCount());
}
bool IsoHasher::ComputeTrackHash(Track& track, ProgressCallback* callback)
{
// use 2048 byte reads for DVDs, otherwise 2352 raw.
const int read_mode = m_is_cd ? CDVD_MODE_2352 : CDVD_MODE_2048;
const u32 sector_size = m_is_cd ? 2352 : 2048;
std::vector<u8> sector_buffer(sector_size);
const u32 update_interval = std::max<u32>(track.sectors / 100u, 1u);
callback->SetFormattedStatusText("Computing hash for track %u...", track.number);
callback->SetProgressRange(track.sectors);
MD5Digest md5;
for (u32 i = 0; i < track.sectors; i++)
{
if (callback->IsCancelled())
return false;
const u32 lsn = track.start_lsn + i;
if (DoCDVDreadSector(sector_buffer.data(), lsn, read_mode) != 0)
{
callback->DisplayFormattedModalError("Read error at LSN %u", lsn);
return false;
}
md5.Update(sector_buffer.data(), sector_size);
if ((i % update_interval) == 0)
callback->SetProgressValue(i);
}
u8 digest[16];
md5.Final(digest);
track.hash =
fmt::format("{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], digest[8],
digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]);
callback->SetProgressValue(track.sectors);
return true;
}

61
pcsx2/CDVD/IsoHasher.h Normal file
View File

@ -0,0 +1,61 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/ProgressCallback.h"
#include <string>
#include <vector>
class Error;
class IsoHasher
{
public:
struct Track
{
u32 number;
u32 type;
u32 start_lsn;
u32 sectors;
u64 size;
std::string hash;
};
public:
IsoHasher();
~IsoHasher();
static std::string_view GetTrackTypeString(u32 type);
const u32 GetTrackCount() const { return static_cast<u32>(m_tracks.size()); }
const Track& GetTrack(u32 n) const { return m_tracks.at(n); }
const std::vector<Track>& GetTracks() const { return m_tracks; }
bool IsCD() const { return m_is_cd; }
bool Open(std::string iso_path, Error* error = nullptr);
void Close();
void ComputeHashes(ProgressCallback* callback = ProgressCallback::NullProgressCallback);
private:
bool ComputeTrackHash(Track& track, ProgressCallback* callback);
std::vector<Track> m_tracks;
bool m_is_open = false;
bool m_is_cd = false;
};

View File

@ -247,6 +247,7 @@ set(pcsx2CDVDSources
CDVD/CDVDisoReader.cpp
CDVD/CDVDdiscThread.cpp
CDVD/InputIsoFile.cpp
CDVD/IsoHasher.cpp
CDVD/IsoReader.cpp
CDVD/OutputIsoFile.cpp
CDVD/ChunksCache.cpp
@ -271,6 +272,7 @@ set(pcsx2CDVDHeaders
CDVD/GzippedFileReader.h
CDVD/ThreadedFileReader.h
CDVD/IsoFileFormats.h
CDVD/IsoHasher.h
CDVD/IsoReader.h
CDVD/zlib_indexed.h
)

View File

@ -122,6 +122,7 @@
<ClCompile Include="CDVD\CsoFileReader.cpp" />
<ClCompile Include="CDVD\GzippedFileReader.cpp" />
<ClCompile Include="CDVD\IsoReader.cpp" />
<ClCompile Include="CDVD\IsoHasher.cpp" />
<ClCompile Include="CDVD\OutputIsoFile.cpp" />
<ClCompile Include="CDVD\ThreadedFileReader.cpp" />
<ClCompile Include="CDVD\Linux\DriveUtility.cpp">
@ -483,6 +484,7 @@
<ClInclude Include="CDVD\ChdFileReader.h" />
<ClInclude Include="CDVD\GzippedFileReader.h" />
<ClInclude Include="CDVD\IsoReader.h" />
<ClInclude Include="CDVD\IsoHasher.h" />
<ClInclude Include="CDVD\ThreadedFileReader.h" />
<ClInclude Include="CDVD\zlib_indexed.h" />
<ClInclude Include="DebugTools\Breakpoints.h" />

View File

@ -109,9 +109,6 @@
<Filter Include="System\Ps2\iCore">
<UniqueIdentifier>{5e741f2d-9e0b-4e43-b2a2-44a8370e1546}</UniqueIdentifier>
</Filter>
<Filter Include="System\IsoFS">
<UniqueIdentifier>{c5237754-2509-4291-b869-c5dacc1a8aba}</UniqueIdentifier>
</Filter>
<Filter Include="System\Ps2\Iop\CDVD\Windows">
<UniqueIdentifier>{be861049-a142-4650-85a5-a2fdd4eef011}</UniqueIdentifier>
</Filter>
@ -1409,7 +1406,12 @@
<ClCompile Include="ImGui\ImGuiFullscreen.cpp">
<Filter>Misc\ImGui</Filter>
</ClCompile>
<ClCompile Include="CDVD\IsoReader.cpp" />
<ClCompile Include="CDVD\IsoHasher.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
<ClCompile Include="CDVD\IsoReader.cpp">
<Filter>System\ISO</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">
@ -2328,7 +2330,12 @@
<ClInclude Include="ImGui\ImGuiFullscreen.h">
<Filter>Misc\ImGui</Filter>
</ClInclude>
<ClInclude Include="CDVD\IsoReader.h" />
<ClInclude Include="CDVD\IsoHasher.h">
<Filter>System\ISO</Filter>
</ClInclude>
<ClInclude Include="CDVD\IsoReader.h">
<Filter>System\ISO</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuildStep Include="rdebug\deci2.h">