DirectoryBlob: Create a DiscContent class for use in m_virtual_disc

This commit is contained in:
JosJuice 2017-06-08 16:07:01 +02:00
parent b56214789e
commit e1321b131d
2 changed files with 88 additions and 39 deletions

View file

@ -10,8 +10,8 @@
#include <cstddef>
#include <cstring>
#include <locale>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
@ -49,6 +49,50 @@ const std::array<u32, 10> PARTITION_TABLE = {
{Common::swap32(1), Common::swap32((PARTITION_TABLE_ADDRESS + 0x20) >> 2), 0, 0, 0, 0, 0, 0,
Common::swap32(GAME_PARTITION_ADDRESS >> 2), 0}};
DiscContent::DiscContent(u64 offset, u64 size, const std::string& path)
: m_offset(offset), m_size(size), m_path(path)
{
}
DiscContent::DiscContent(u64 offset) : m_offset(offset)
{
}
u64 DiscContent::GetOffset() const
{
return m_offset;
}
u64 DiscContent::GetSize() const
{
return m_size;
}
bool DiscContent::Read(u64* offset, u64* length, u8** buffer) const
{
if (m_size == 0)
return true;
_dbg_assert_(DISCIO, *offset >= m_offset);
const u64 offset_in_content = *offset - m_offset;
if (offset_in_content < m_size)
{
const u64 bytes_to_read = std::min(m_size - offset_in_content, *length);
File::IOFile file(m_path, "rb");
file.Seek(offset_in_content, SEEK_SET);
if (!file.ReadBytes(*buffer, bytes_to_read))
return false;
*length -= bytes_to_read;
*buffer += bytes_to_read;
*offset += bytes_to_read;
}
return true;
}
static bool PathCharactersEqual(char a, char b)
{
return a == b
@ -140,49 +184,29 @@ bool DirectoryBlobReader::ReadPartition(u64 offset, u64 length, u8* buffer)
WriteToBuffer(m_fst_address, m_fst_data.size(), m_fst_data.data(), &offset, &length, &buffer);
}
if (m_virtual_disk.empty())
if (m_virtual_disc.empty())
return true;
// Determine which file the offset refers to
std::map<u64, std::string>::const_iterator fileIter = m_virtual_disk.lower_bound(offset);
if (fileIter->first > offset && fileIter != m_virtual_disk.begin())
--fileIter;
// Determine which DiscContent the offset refers to
std::set<DiscContent>::const_iterator it = m_virtual_disc.lower_bound(DiscContent(offset));
if (it->GetOffset() > offset && it != m_virtual_disc.begin())
--it;
// zero fill to start of file data
PadToAddress(fileIter->first, &offset, &length, &buffer);
PadToAddress(it->GetOffset(), &offset, &length, &buffer);
while (fileIter != m_virtual_disk.end() && length > 0)
while (it != m_virtual_disc.end() && length > 0)
{
_dbg_assert_(DVDINTERFACE, fileIter->first <= offset);
u64 fileOffset = offset - fileIter->first;
const std::string fileName = fileIter->second;
File::IOFile file(fileName, "rb");
if (!file)
_dbg_assert_(DVDINTERFACE, it->GetOffset() <= offset);
if (!it->Read(&offset, &length, &buffer))
return false;
u64 fileSize = file.GetSize();
++it;
if (fileOffset < fileSize)
if (it != m_virtual_disc.end())
{
u64 fileBytes = std::min(fileSize - fileOffset, length);
if (!file.Seek(fileOffset, SEEK_SET))
return false;
if (!file.ReadBytes(buffer, fileBytes))
return false;
length -= fileBytes;
buffer += fileBytes;
offset += fileBytes;
}
++fileIter;
if (fileIter != m_virtual_disk.end())
{
_dbg_assert_(DVDINTERFACE, fileIter->first >= offset);
PadToAddress(fileIter->first, &offset, &length, &buffer);
_dbg_assert_(DVDINTERFACE, it->GetOffset() >= offset);
PadToAddress(it->GetOffset(), &offset, &length, &buffer);
}
}
@ -468,9 +492,9 @@ void DirectoryBlobReader::WriteDirectory(const File::FSTEntry& parent_entry, u32
m_address_shift);
WriteEntryName(name_offset, entry.virtualName);
// write entry to virtual disk
_dbg_assert_(DVDINTERFACE, m_virtual_disk.find(*data_offset) == m_virtual_disk.end());
m_virtual_disk.emplace(*data_offset, entry.physicalName);
// write entry to virtual disc
auto result = m_virtual_disc.emplace(*data_offset, entry.size, entry.physicalName);
_dbg_assert_(DISCIO, result.second); // Check that this offset wasn't already occupied
// 32 KiB aligned - many games are fine with less alignment, but not all
*data_offset = Common::AlignUp(*data_offset + std::max<u64>(entry.size, 1ull), 0x8000ull);

View file

@ -4,9 +4,10 @@
#pragma once
#include <map>
#include <cstddef>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
@ -22,6 +23,30 @@ class IOFile;
namespace DiscIO
{
class DiscContent
{
public:
DiscContent(u64 offset, u64 size, const std::string& path);
// Provided because it's convenient when searching for DiscContent in an std::set
explicit DiscContent(u64 offset);
u64 GetOffset() const;
u64 GetSize() const;
bool Read(u64* offset, u64* length, u8** buffer) const;
bool operator==(const DiscContent& other) const { return m_offset == other.m_offset; }
bool operator!=(const DiscContent& other) const { return !(*this == other); }
bool operator<(const DiscContent& other) const { return m_offset < other.m_offset; }
bool operator>(const DiscContent& other) const { return other < *this; }
bool operator<=(const DiscContent& other) const { return !(*this < other); }
bool operator>=(const DiscContent& other) const { return !(*this > other); }
private:
u64 m_offset;
u64 m_size = 0;
std::string m_path;
};
class DirectoryBlobReader : public BlobReader
{
public:
@ -70,7 +95,7 @@ private:
std::string m_root_directory;
std::map<u64, std::string> m_virtual_disk;
std::set<DiscContent> m_virtual_disc;
bool m_is_wii = false;