Common: Add a CD image hasher class
This commit is contained in:
parent
06f5c3710d
commit
8b04b74f27
|
@ -13,6 +13,8 @@ add_library(common
|
|||
cd_image_bin.cpp
|
||||
cd_image_cue.cpp
|
||||
cd_image_chd.cpp
|
||||
cd_image_hasher.cpp
|
||||
cd_image_hasher.h
|
||||
cd_subchannel_replacement.cpp
|
||||
cd_subchannel_replacement.h
|
||||
cd_xa.cpp
|
||||
|
|
|
@ -72,6 +72,28 @@ CDImage::TrackMode CDImage::GetTrackMode(u8 track) const
|
|||
return m_tracks[track - 1].mode;
|
||||
}
|
||||
|
||||
CDImage::LBA CDImage::GetTrackIndexPosition(u8 track, u8 index) const
|
||||
{
|
||||
for (const Index& current_index : m_indices)
|
||||
{
|
||||
if (current_index.track_number == track && current_index.index_number == index)
|
||||
return current_index.start_lba_on_disc;
|
||||
}
|
||||
|
||||
return m_lba_count;
|
||||
}
|
||||
|
||||
CDImage::LBA CDImage::GetTrackIndexLength(u8 track, u8 index) const
|
||||
{
|
||||
for (const Index& current_index : m_indices)
|
||||
{
|
||||
if (current_index.track_number == track && current_index.index_number == index)
|
||||
return current_index.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CDImage::Seek(LBA lba)
|
||||
{
|
||||
const Index* new_index;
|
||||
|
|
|
@ -182,6 +182,8 @@ public:
|
|||
LBA GetTrackLength(u8 track) const;
|
||||
Position GetTrackMSFLength(u8 track) const;
|
||||
TrackMode GetTrackMode(u8 track) const;
|
||||
LBA GetTrackIndexPosition(u8 track, u8 index) const;
|
||||
LBA GetTrackIndexLength(u8 track, u8 index) const;
|
||||
u32 GetFirstTrackNumber() const { return m_tracks.front().track_number; }
|
||||
u32 GetLastTrackNumber() const { return m_tracks.back().track_number; }
|
||||
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
#include "cd_image_hasher.h"
|
||||
#include "cd_image.h"
|
||||
#include "md5_digest.h"
|
||||
#include "string_util.h"
|
||||
|
||||
namespace CDImageHasher {
|
||||
|
||||
static bool ReadIndex(CDImage* image, u8 track, u8 index, MD5Digest* digest, ProgressCallback* progress_callback)
|
||||
{
|
||||
const CDImage::LBA index_start = image->GetTrackIndexPosition(track, index);
|
||||
const u32 index_length = image->GetTrackIndexLength(track, index);
|
||||
const u32 update_interval = std::max<u32>(index_length / 100u, 1u);
|
||||
|
||||
progress_callback->SetFormattedStatusText("Computing hash for track %u/index %u...", track, index);
|
||||
progress_callback->SetProgressRange(index_length);
|
||||
|
||||
if (!image->Seek(index_start))
|
||||
{
|
||||
progress_callback->DisplayFormattedModalError("Failed to seek to sector %u for track %u index %u", index_start,
|
||||
track, index);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<u8, CDImage::RAW_SECTOR_SIZE> sector;
|
||||
for (u32 lba = 0; lba < index_length; lba++)
|
||||
{
|
||||
if ((lba % update_interval) == 0)
|
||||
progress_callback->SetProgressValue(lba);
|
||||
|
||||
if (!image->ReadRawSector(sector.data()))
|
||||
{
|
||||
progress_callback->DisplayFormattedModalError("Failed to read sector %u from image", image->GetPositionOnDisc());
|
||||
return false;
|
||||
}
|
||||
|
||||
digest->Update(sector.data(), static_cast<u32>(sector.size()));
|
||||
}
|
||||
|
||||
progress_callback->SetProgressValue(index_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ReadTrack(CDImage* image, u8 track, MD5Digest* digest, ProgressCallback* progress_callback)
|
||||
{
|
||||
static constexpr u8 INDICES_TO_READ = 2;
|
||||
|
||||
progress_callback->PushState();
|
||||
|
||||
progress_callback->SetProgressRange(2);
|
||||
for (u8 index = 0; index < INDICES_TO_READ; index++)
|
||||
{
|
||||
progress_callback->SetProgressValue(index);
|
||||
|
||||
// skip index 0 if data track
|
||||
if (index == 0 && image->GetTrackMode(track) != CDImage::TrackMode::Audio)
|
||||
continue;
|
||||
|
||||
progress_callback->PushState();
|
||||
if (!ReadIndex(image, track, index, digest, progress_callback))
|
||||
{
|
||||
progress_callback->PopState();
|
||||
progress_callback->PopState();
|
||||
return false;
|
||||
}
|
||||
|
||||
progress_callback->PopState();
|
||||
}
|
||||
|
||||
progress_callback->SetProgressValue(INDICES_TO_READ);
|
||||
progress_callback->PopState();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string HashToString(const Hash& hash)
|
||||
{
|
||||
return StringUtil::StdStringFromFormat("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", hash[0],
|
||||
hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8],
|
||||
hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]);
|
||||
}
|
||||
|
||||
bool GetImageHash(CDImage* image, Hash* out_hash,
|
||||
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
|
||||
{
|
||||
MD5Digest digest;
|
||||
|
||||
progress_callback->SetProgressRange(image->GetTrackCount());
|
||||
progress_callback->SetProgressValue(0);
|
||||
progress_callback->PushState();
|
||||
|
||||
for (u32 i = 1; i <= image->GetTrackCount(); i++)
|
||||
{
|
||||
progress_callback->SetProgressValue(i - 1);
|
||||
if (!ReadTrack(image, i, &digest, progress_callback))
|
||||
{
|
||||
progress_callback->PopState();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
progress_callback->SetProgressValue(image->GetTrackCount());
|
||||
digest.Final(out_hash->data());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetTrackHash(CDImage* image, u8 track, Hash* out_hash,
|
||||
ProgressCallback* progress_callback /*= ProgressCallback::NullProgressCallback*/)
|
||||
{
|
||||
MD5Digest digest;
|
||||
if (!ReadTrack(image, track, &digest, progress_callback))
|
||||
return false;
|
||||
|
||||
digest.Final(out_hash->data());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace CDImageHasher
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include "progress_callback.h"
|
||||
#include "types.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
class CDImage;
|
||||
|
||||
namespace CDImageHasher {
|
||||
|
||||
using Hash = std::array<u8, 16>;
|
||||
std::string HashToString(const Hash& hash);
|
||||
|
||||
bool GetImageHash(CDImage* image, Hash* out_hash,
|
||||
ProgressCallback* progress_callback = ProgressCallback::NullProgressCallback);
|
||||
bool GetTrackHash(CDImage* image, u8 track, Hash* out_hash,
|
||||
ProgressCallback* progress_callback = ProgressCallback::NullProgressCallback);
|
||||
|
||||
} // namespace CDImageHasher
|
|
@ -42,6 +42,7 @@
|
|||
<ClInclude Include="bitutils.h" />
|
||||
<ClInclude Include="byte_stream.h" />
|
||||
<ClInclude Include="cd_image.h" />
|
||||
<ClInclude Include="cd_image_hasher.h" />
|
||||
<ClInclude Include="cpu_detect.h" />
|
||||
<ClInclude Include="cubeb_audio_stream.h" />
|
||||
<ClInclude Include="d3d11\shader_cache.h" />
|
||||
|
@ -86,6 +87,7 @@
|
|||
<ClCompile Include="cd_image_bin.cpp" />
|
||||
<ClCompile Include="cd_image_chd.cpp" />
|
||||
<ClCompile Include="cd_image_cue.cpp" />
|
||||
<ClCompile Include="cd_image_hasher.cpp" />
|
||||
<ClCompile Include="cubeb_audio_stream.cpp" />
|
||||
<ClCompile Include="d3d11\shader_cache.cpp" />
|
||||
<ClCompile Include="d3d11\shader_compiler.cpp" />
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<Filter>gl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="window_info.h" />
|
||||
<ClInclude Include="cd_image_hasher.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="jit_code_buffer.cpp" />
|
||||
|
@ -124,6 +125,7 @@
|
|||
<ClCompile Include="gl\context.cpp">
|
||||
<Filter>gl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cd_image_hasher.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="bitfield.natvis" />
|
||||
|
|
Loading…
Reference in New Issue