Merge pull request #933 from lioncash/prefix
DiscIO: Prefix class member variables with "m_"
This commit is contained in:
commit
b026217984
|
@ -27,15 +27,15 @@ void SectorReader::SetSectorSize(int blocksize)
|
|||
{
|
||||
for (int i = 0; i < CACHE_SIZE; i++)
|
||||
{
|
||||
cache[i] = new u8[blocksize];
|
||||
cache_tags[i] = (u64)(s64) - 1;
|
||||
m_cache[i] = new u8[blocksize];
|
||||
m_cache_tags[i] = (u64)(s64) - 1;
|
||||
}
|
||||
m_blocksize = blocksize;
|
||||
}
|
||||
|
||||
SectorReader::~SectorReader()
|
||||
{
|
||||
for (u8*& block : cache)
|
||||
for (u8*& block : m_cache)
|
||||
{
|
||||
delete [] block;
|
||||
}
|
||||
|
@ -44,15 +44,15 @@ SectorReader::~SectorReader()
|
|||
const u8 *SectorReader::GetBlockData(u64 block_num)
|
||||
{
|
||||
// TODO : Expand usage of the cache to more than one block :P
|
||||
if (cache_tags[0] == block_num)
|
||||
if (m_cache_tags[0] == block_num)
|
||||
{
|
||||
return cache[0];
|
||||
return m_cache[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBlock(block_num, cache[0]);
|
||||
cache_tags[0] = block_num;
|
||||
return cache[0];
|
||||
GetBlock(block_num, m_cache[0]);
|
||||
m_cache_tags[0] = block_num;
|
||||
return m_cache[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,19 +41,6 @@ protected:
|
|||
// Multi-block reads are not cached.
|
||||
class SectorReader : public IBlobReader
|
||||
{
|
||||
private:
|
||||
enum { CACHE_SIZE = 32 };
|
||||
int m_blocksize;
|
||||
u8* cache[CACHE_SIZE];
|
||||
u64 cache_tags[CACHE_SIZE];
|
||||
int cache_age[CACHE_SIZE];
|
||||
|
||||
protected:
|
||||
void SetSectorSize(int blocksize);
|
||||
virtual void GetBlock(u64 block_num, u8 *out) = 0;
|
||||
// This one is uncached. The default implementation is to simply call GetBlockData multiple times and memcpy.
|
||||
virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr);
|
||||
|
||||
public:
|
||||
virtual ~SectorReader();
|
||||
|
||||
|
@ -61,6 +48,19 @@ public:
|
|||
const u8 *GetBlockData(u64 block_num);
|
||||
virtual bool Read(u64 offset, u64 size, u8 *out_ptr) override;
|
||||
friend class DriveReader;
|
||||
|
||||
protected:
|
||||
void SetSectorSize(int blocksize);
|
||||
virtual void GetBlock(u64 block_num, u8 *out) = 0;
|
||||
// This one is uncached. The default implementation is to simply call GetBlockData multiple times and memcpy.
|
||||
virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr);
|
||||
|
||||
private:
|
||||
enum { CACHE_SIZE = 32 };
|
||||
int m_blocksize;
|
||||
u8* m_cache[CACHE_SIZE];
|
||||
u64 m_cache_tags[CACHE_SIZE];
|
||||
int m_cache_age[CACHE_SIZE];
|
||||
};
|
||||
|
||||
// Factory function - examines the path to choose the right type of IBlobReader, and returns one.
|
||||
|
|
|
@ -26,29 +26,29 @@
|
|||
namespace DiscIO
|
||||
{
|
||||
|
||||
CompressedBlobReader::CompressedBlobReader(const std::string& filename) : file_name(filename)
|
||||
CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file_name(filename)
|
||||
{
|
||||
m_file.Open(filename, "rb");
|
||||
file_size = File::GetSize(filename);
|
||||
m_file.ReadArray(&header, 1);
|
||||
m_file_size = File::GetSize(filename);
|
||||
m_file.ReadArray(&m_header, 1);
|
||||
|
||||
SetSectorSize(header.block_size);
|
||||
SetSectorSize(m_header.block_size);
|
||||
|
||||
// cache block pointers and hashes
|
||||
block_pointers = new u64[header.num_blocks];
|
||||
m_file.ReadArray(block_pointers, header.num_blocks);
|
||||
hashes = new u32[header.num_blocks];
|
||||
m_file.ReadArray(hashes, header.num_blocks);
|
||||
m_block_pointers = new u64[m_header.num_blocks];
|
||||
m_file.ReadArray(m_block_pointers, m_header.num_blocks);
|
||||
m_hashes = new u32[m_header.num_blocks];
|
||||
m_file.ReadArray(m_hashes, m_header.num_blocks);
|
||||
|
||||
data_offset = (sizeof(CompressedBlobHeader))
|
||||
+ (sizeof(u64)) * header.num_blocks // skip block pointers
|
||||
+ (sizeof(u32)) * header.num_blocks; // skip hashes
|
||||
m_data_offset = (sizeof(CompressedBlobHeader))
|
||||
+ (sizeof(u64)) * m_header.num_blocks // skip block pointers
|
||||
+ (sizeof(u32)) * m_header.num_blocks; // skip hashes
|
||||
|
||||
// A compressed block is never ever longer than a decompressed block, so just header.block_size should be fine.
|
||||
// I still add some safety margin.
|
||||
zlib_buffer_size = header.block_size + 64;
|
||||
zlib_buffer = new u8[zlib_buffer_size];
|
||||
memset(zlib_buffer, 0, zlib_buffer_size);
|
||||
m_zlib_buffer_size = m_header.block_size + 64;
|
||||
m_zlib_buffer = new u8[m_zlib_buffer_size];
|
||||
memset(m_zlib_buffer, 0, m_zlib_buffer_size);
|
||||
}
|
||||
|
||||
CompressedBlobReader* CompressedBlobReader::Create(const std::string& filename)
|
||||
|
@ -61,19 +61,19 @@ CompressedBlobReader* CompressedBlobReader::Create(const std::string& filename)
|
|||
|
||||
CompressedBlobReader::~CompressedBlobReader()
|
||||
{
|
||||
delete [] zlib_buffer;
|
||||
delete [] block_pointers;
|
||||
delete [] hashes;
|
||||
delete [] m_zlib_buffer;
|
||||
delete [] m_block_pointers;
|
||||
delete [] m_hashes;
|
||||
}
|
||||
|
||||
// IMPORTANT: Calling this function invalidates all earlier pointers gotten from this function.
|
||||
u64 CompressedBlobReader::GetBlockCompressedSize(u64 block_num) const
|
||||
{
|
||||
u64 start = block_pointers[block_num];
|
||||
if (block_num < header.num_blocks - 1)
|
||||
return block_pointers[block_num + 1] - start;
|
||||
else if (block_num == header.num_blocks - 1)
|
||||
return header.compressed_data_size - start;
|
||||
u64 start = m_block_pointers[block_num];
|
||||
if (block_num < m_header.num_blocks - 1)
|
||||
return m_block_pointers[block_num + 1] - start;
|
||||
else if (block_num == m_header.num_blocks - 1)
|
||||
return m_header.compressed_data_size - start;
|
||||
else
|
||||
PanicAlert("GetBlockCompressedSize - illegal block number %i", (int)block_num);
|
||||
return 0;
|
||||
|
@ -83,32 +83,32 @@ void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
|
|||
{
|
||||
bool uncompressed = false;
|
||||
u32 comp_block_size = (u32)GetBlockCompressedSize(block_num);
|
||||
u64 offset = block_pointers[block_num] + data_offset;
|
||||
u64 offset = m_block_pointers[block_num] + m_data_offset;
|
||||
|
||||
if (offset & (1ULL << 63))
|
||||
{
|
||||
if (comp_block_size != header.block_size)
|
||||
if (comp_block_size != m_header.block_size)
|
||||
PanicAlert("Uncompressed block with wrong size");
|
||||
uncompressed = true;
|
||||
offset &= ~(1ULL << 63);
|
||||
}
|
||||
|
||||
// clear unused part of zlib buffer. maybe this can be deleted when it works fully.
|
||||
memset(zlib_buffer + comp_block_size, 0, zlib_buffer_size - comp_block_size);
|
||||
memset(m_zlib_buffer + comp_block_size, 0, m_zlib_buffer_size - comp_block_size);
|
||||
|
||||
m_file.Seek(offset, SEEK_SET);
|
||||
m_file.ReadBytes(zlib_buffer, comp_block_size);
|
||||
m_file.ReadBytes(m_zlib_buffer, comp_block_size);
|
||||
|
||||
u8* source = zlib_buffer;
|
||||
u8* source = m_zlib_buffer;
|
||||
u8* dest = out_ptr;
|
||||
|
||||
// First, check hash.
|
||||
u32 block_hash = HashAdler32(source, comp_block_size);
|
||||
if (block_hash != hashes[block_num])
|
||||
if (block_hash != m_hashes[block_num])
|
||||
PanicAlert("Hash of block %" PRIu64 " is %08x instead of %08x.\n"
|
||||
"Your ISO, %s, is corrupt.",
|
||||
block_num, block_hash, hashes[block_num],
|
||||
file_name.c_str());
|
||||
block_num, block_hash, m_hashes[block_num],
|
||||
m_file_name.c_str());
|
||||
|
||||
if (uncompressed)
|
||||
{
|
||||
|
@ -120,15 +120,15 @@ void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
|
|||
memset(&z, 0, sizeof(z));
|
||||
z.next_in = source;
|
||||
z.avail_in = comp_block_size;
|
||||
if (z.avail_in > header.block_size)
|
||||
if (z.avail_in > m_header.block_size)
|
||||
{
|
||||
PanicAlert("We have a problem");
|
||||
}
|
||||
z.next_out = dest;
|
||||
z.avail_out = header.block_size;
|
||||
z.avail_out = m_header.block_size;
|
||||
inflateInit(&z);
|
||||
int status = inflate(&z, Z_FULL_FLUSH);
|
||||
u32 uncomp_size = header.block_size - z.avail_out;
|
||||
u32 uncomp_size = m_header.block_size - z.avail_out;
|
||||
if (status != Z_STREAM_END)
|
||||
{
|
||||
// this seem to fire wrongly from time to time
|
||||
|
@ -136,7 +136,7 @@ void CompressedBlobReader::GetBlock(u64 block_num, u8 *out_ptr)
|
|||
PanicAlert("Failure reading block %" PRIu64 " - out of data and not at end.", block_num);
|
||||
}
|
||||
inflateEnd(&z);
|
||||
if (uncomp_size != header.block_size)
|
||||
if (uncomp_size != m_header.block_size)
|
||||
PanicAlert("Wrong block size");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,23 +48,23 @@ class CompressedBlobReader : public SectorReader
|
|||
public:
|
||||
static CompressedBlobReader* Create(const std::string& filename);
|
||||
~CompressedBlobReader();
|
||||
const CompressedBlobHeader &GetHeader() const { return header; }
|
||||
u64 GetDataSize() const override { return header.data_size; }
|
||||
u64 GetRawSize() const override { return file_size; }
|
||||
const CompressedBlobHeader &GetHeader() const { return m_header; }
|
||||
u64 GetDataSize() const override { return m_header.data_size; }
|
||||
u64 GetRawSize() const override { return m_file_size; }
|
||||
u64 GetBlockCompressedSize(u64 block_num) const;
|
||||
void GetBlock(u64 block_num, u8* out_ptr) override;
|
||||
private:
|
||||
CompressedBlobReader(const std::string& filename);
|
||||
|
||||
CompressedBlobHeader header;
|
||||
u64* block_pointers;
|
||||
u32* hashes;
|
||||
int data_offset;
|
||||
CompressedBlobHeader m_header;
|
||||
u64* m_block_pointers;
|
||||
u32* m_hashes;
|
||||
int m_data_offset;
|
||||
File::IOFile m_file;
|
||||
u64 file_size;
|
||||
u8* zlib_buffer;
|
||||
int zlib_buffer_size;
|
||||
std::string file_name;
|
||||
u64 m_file_size;
|
||||
u8* m_zlib_buffer;
|
||||
int m_zlib_buffer_size;
|
||||
std::string m_file_name;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -23,20 +23,20 @@ DriveReader::DriveReader(const std::string& drive)
|
|||
#ifdef _WIN32
|
||||
SectorReader::SetSectorSize(2048);
|
||||
auto const path = UTF8ToTStr(std::string("\\\\.\\") + drive);
|
||||
hDisc = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
m_disc_handle = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
nullptr, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr);
|
||||
if (hDisc != INVALID_HANDLE_VALUE)
|
||||
if (m_disc_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Do a test read to make sure everything is OK, since it seems you can get
|
||||
// handles to empty drives.
|
||||
DWORD not_used;
|
||||
u8 *buffer = new u8[m_blocksize];
|
||||
if (!ReadFile(hDisc, buffer, m_blocksize, (LPDWORD)¬_used, nullptr))
|
||||
if (!ReadFile(m_disc_handle, buffer, m_blocksize, (LPDWORD)¬_used, nullptr))
|
||||
{
|
||||
delete [] buffer;
|
||||
// OK, something is wrong.
|
||||
CloseHandle(hDisc);
|
||||
hDisc = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(m_disc_handle);
|
||||
m_disc_handle = INVALID_HANDLE_VALUE;
|
||||
return;
|
||||
}
|
||||
delete [] buffer;
|
||||
|
@ -44,15 +44,15 @@ DriveReader::DriveReader(const std::string& drive)
|
|||
#ifdef _LOCKDRIVE // Do we want to lock the drive?
|
||||
// Lock the compact disc in the CD-ROM drive to prevent accidental
|
||||
// removal while reading from it.
|
||||
pmrLockCDROM.PreventMediaRemoval = TRUE;
|
||||
DeviceIoControl(hDisc, IOCTL_CDROM_MEDIA_REMOVAL,
|
||||
&pmrLockCDROM, sizeof(pmrLockCDROM), nullptr,
|
||||
m_lock_cdrom.PreventMediaRemoval = TRUE;
|
||||
DeviceIoControl(m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL,
|
||||
&m_lock_cdrom, sizeof(m_lock_cdrom), nullptr,
|
||||
0, &dwNotUsed, nullptr);
|
||||
#endif
|
||||
#else
|
||||
SectorReader::SetSectorSize(2048);
|
||||
file_.Open(drive, "rb");
|
||||
if (file_)
|
||||
m_file.Open(drive, "rb");
|
||||
if (m_file)
|
||||
{
|
||||
#endif
|
||||
}
|
||||
|
@ -67,18 +67,18 @@ DriveReader::~DriveReader()
|
|||
#ifdef _WIN32
|
||||
#ifdef _LOCKDRIVE // Do we want to lock the drive?
|
||||
// Unlock the disc in the CD-ROM drive.
|
||||
pmrLockCDROM.PreventMediaRemoval = FALSE;
|
||||
DeviceIoControl (hDisc, IOCTL_CDROM_MEDIA_REMOVAL,
|
||||
&pmrLockCDROM, sizeof(pmrLockCDROM), nullptr,
|
||||
m_lock_cdrom.PreventMediaRemoval = FALSE;
|
||||
DeviceIoControl (m_disc_handle, IOCTL_CDROM_MEDIA_REMOVAL,
|
||||
&m_lock_cdrom, sizeof(m_lock_cdrom), nullptr,
|
||||
0, &dwNotUsed, nullptr);
|
||||
#endif
|
||||
if (hDisc != INVALID_HANDLE_VALUE)
|
||||
if (m_disc_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(hDisc);
|
||||
hDisc = INVALID_HANDLE_VALUE;
|
||||
CloseHandle(m_disc_handle);
|
||||
m_disc_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
file_.Close();
|
||||
m_file.Close();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -103,12 +103,12 @@ void DriveReader::GetBlock(u64 block_num, u8* out_ptr)
|
|||
u64 offset = m_blocksize * block_num;
|
||||
LONG off_low = (LONG)offset & 0xFFFFFFFF;
|
||||
LONG off_high = (LONG)(offset >> 32);
|
||||
SetFilePointer(hDisc, off_low, &off_high, FILE_BEGIN);
|
||||
if (!ReadFile(hDisc, lpSector, m_blocksize, (LPDWORD)&NotUsed, nullptr))
|
||||
SetFilePointer(m_disc_handle, off_low, &off_high, FILE_BEGIN);
|
||||
if (!ReadFile(m_disc_handle, lpSector, m_blocksize, (LPDWORD)&NotUsed, nullptr))
|
||||
PanicAlertT("Disc Read Error");
|
||||
#else
|
||||
file_.Seek(m_blocksize * block_num, SEEK_SET);
|
||||
file_.ReadBytes(lpSector, m_blocksize);
|
||||
m_file.Seek(m_blocksize * block_num, SEEK_SET);
|
||||
m_file.ReadBytes(lpSector, m_blocksize);
|
||||
#endif
|
||||
memcpy(out_ptr, lpSector, m_blocksize);
|
||||
delete[] lpSector;
|
||||
|
@ -121,15 +121,15 @@ bool DriveReader::ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8* o
|
|||
u64 offset = m_blocksize * block_num;
|
||||
LONG off_low = (LONG)offset & 0xFFFFFFFF;
|
||||
LONG off_high = (LONG)(offset >> 32);
|
||||
SetFilePointer(hDisc, off_low, &off_high, FILE_BEGIN);
|
||||
if (!ReadFile(hDisc, out_ptr, (DWORD)(m_blocksize * num_blocks), (LPDWORD)&NotUsed, nullptr))
|
||||
SetFilePointer(m_disc_handle, off_low, &off_high, FILE_BEGIN);
|
||||
if (!ReadFile(m_disc_handle, out_ptr, (DWORD)(m_blocksize * num_blocks), (LPDWORD)&NotUsed, nullptr))
|
||||
{
|
||||
PanicAlertT("Disc Read Error");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
fseeko(file_.GetHandle(), m_blocksize*block_num, SEEK_SET);
|
||||
if (fread(out_ptr, 1, m_blocksize * num_blocks, file_.GetHandle()) != m_blocksize * num_blocks)
|
||||
fseeko(m_file.GetHandle(), (m_blocksize * block_num), SEEK_SET);
|
||||
if (fread(out_ptr, 1, (m_blocksize * num_blocks), m_file.GetHandle()) != (m_blocksize * num_blocks))
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
|
|
|
@ -20,27 +20,27 @@ namespace DiscIO
|
|||
|
||||
class DriveReader : public SectorReader
|
||||
{
|
||||
public:
|
||||
static DriveReader* Create(const std::string& drive);
|
||||
~DriveReader();
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
|
||||
virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr) override;
|
||||
|
||||
private:
|
||||
DriveReader(const std::string& drive);
|
||||
void GetBlock(u64 block_num, u8 *out_ptr) override;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hDisc;
|
||||
PREVENT_MEDIA_REMOVAL pmrLockCDROM;
|
||||
bool IsOK() {return hDisc != INVALID_HANDLE_VALUE;}
|
||||
HANDLE m_disc_handle;
|
||||
PREVENT_MEDIA_REMOVAL m_lock_cdrom;
|
||||
bool IsOK() { return m_disc_handle != INVALID_HANDLE_VALUE; }
|
||||
#else
|
||||
File::IOFile file_;
|
||||
bool IsOK() {return file_ != nullptr;}
|
||||
File::IOFile m_file;
|
||||
bool IsOK() { return m_file != nullptr; }
|
||||
#endif
|
||||
s64 size;
|
||||
|
||||
public:
|
||||
static DriveReader* Create(const std::string& drive);
|
||||
~DriveReader();
|
||||
u64 GetDataSize() const override { return size; }
|
||||
u64 GetRawSize() const override { return size; }
|
||||
|
||||
virtual bool ReadMultipleAlignedBlocks(u64 block_num, u64 num_blocks, u8 *out_ptr) override;
|
||||
s64 m_size;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -16,17 +16,18 @@ namespace DiscIO
|
|||
|
||||
class PlainFileReader : public IBlobReader
|
||||
{
|
||||
PlainFileReader(std::FILE* file);
|
||||
|
||||
File::IOFile m_file;
|
||||
s64 m_size;
|
||||
|
||||
public:
|
||||
static PlainFileReader* Create(const std::string& filename);
|
||||
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
|
||||
|
||||
private:
|
||||
PlainFileReader(std::FILE* file);
|
||||
|
||||
File::IOFile m_file;
|
||||
s64 m_size;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -37,15 +37,15 @@ CSharedContent::CSharedContent()
|
|||
void CSharedContent::UpdateLocation()
|
||||
{
|
||||
m_Elements.clear();
|
||||
lastID = 0;
|
||||
contentMap = StringFromFormat("%sshared1/content.map", File::GetUserPath(D_WIIUSER_IDX).c_str());
|
||||
m_lastID = 0;
|
||||
m_contentMap = StringFromFormat("%sshared1/content.map", File::GetUserPath(D_WIIUSER_IDX).c_str());
|
||||
|
||||
File::IOFile pFile(contentMap, "rb");
|
||||
File::IOFile pFile(m_contentMap, "rb");
|
||||
SElement Element;
|
||||
while (pFile.ReadArray(&Element, 1))
|
||||
{
|
||||
m_Elements.push_back(Element);
|
||||
lastID++;
|
||||
m_lastID++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,19 +72,19 @@ std::string CSharedContent::AddSharedContent(const u8* _pHash)
|
|||
|
||||
if (strcasecmp(filename.c_str(), "unk") == 0)
|
||||
{
|
||||
std::string id = StringFromFormat("%08x", lastID);
|
||||
std::string id = StringFromFormat("%08x", m_lastID);
|
||||
SElement Element;
|
||||
memcpy(Element.FileName, id.c_str(), 8);
|
||||
memcpy(Element.SHA1Hash, _pHash, 20);
|
||||
m_Elements.push_back(Element);
|
||||
|
||||
File::CreateFullPath(contentMap);
|
||||
File::CreateFullPath(m_contentMap);
|
||||
|
||||
File::IOFile pFile(contentMap, "ab");
|
||||
File::IOFile pFile(m_contentMap, "ab");
|
||||
pFile.WriteArray(&Element, 1);
|
||||
|
||||
filename = StringFromFormat("%sshared1/%s.app", File::GetUserPath(D_WIIUSER_IDX).c_str(), id.c_str());
|
||||
lastID++;
|
||||
m_lastID++;
|
||||
}
|
||||
|
||||
return filename;
|
||||
|
@ -382,14 +382,14 @@ cUIDsys::cUIDsys()
|
|||
void cUIDsys::UpdateLocation()
|
||||
{
|
||||
m_Elements.clear();
|
||||
lastUID = 0x00001000;
|
||||
uidSys = StringFromFormat("%ssys/uid.sys", File::GetUserPath(D_WIIUSER_IDX).c_str());
|
||||
m_lastUID = 0x00001000;
|
||||
m_uidSys = StringFromFormat("%ssys/uid.sys", File::GetUserPath(D_WIIUSER_IDX).c_str());
|
||||
|
||||
File::IOFile pFile(uidSys, "rb");
|
||||
File::IOFile pFile(m_uidSys, "rb");
|
||||
SElement Element;
|
||||
while (pFile.ReadArray(&Element, 1))
|
||||
{
|
||||
*(u32*)&(Element.UID) = Common::swap32(lastUID++);
|
||||
*(u32*)&(Element.UID) = Common::swap32(m_lastUID++);
|
||||
m_Elements.push_back(Element);
|
||||
}
|
||||
pFile.Close();
|
||||
|
@ -397,12 +397,12 @@ void cUIDsys::UpdateLocation()
|
|||
if (m_Elements.empty())
|
||||
{
|
||||
*(u64*)&(Element.titleID) = Common::swap64(TITLEID_SYSMENU);
|
||||
*(u32*)&(Element.UID) = Common::swap32(lastUID++);
|
||||
*(u32*)&(Element.UID) = Common::swap32(m_lastUID++);
|
||||
|
||||
File::CreateFullPath(uidSys);
|
||||
pFile.Open(uidSys, "wb");
|
||||
File::CreateFullPath(m_uidSys);
|
||||
pFile.Open(m_uidSys, "wb");
|
||||
if (!pFile.WriteArray(&Element, 1))
|
||||
ERROR_LOG(DISCIO, "Failed to write to %s", uidSys.c_str());
|
||||
ERROR_LOG(DISCIO, "Failed to write to %s", m_uidSys.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,11 +431,11 @@ void cUIDsys::AddTitle(u64 _TitleID)
|
|||
|
||||
SElement Element;
|
||||
*(u64*)&(Element.titleID) = Common::swap64(_TitleID);
|
||||
*(u32*)&(Element.UID) = Common::swap32(lastUID++);
|
||||
*(u32*)&(Element.UID) = Common::swap32(m_lastUID++);
|
||||
m_Elements.push_back(Element);
|
||||
|
||||
File::CreateFullPath(uidSys);
|
||||
File::IOFile pFile(uidSys, "ab");
|
||||
File::CreateFullPath(m_uidSys);
|
||||
File::IOFile pFile(m_uidSys, "ab");
|
||||
|
||||
if (!pFile.WriteArray(&Element, 1))
|
||||
ERROR_LOG(DISCIO, "fwrite failed");
|
||||
|
|
|
@ -106,8 +106,8 @@ private:
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
u32 lastID;
|
||||
std::string contentMap;
|
||||
u32 m_lastID;
|
||||
std::string m_contentMap;
|
||||
std::vector<SElement> m_Elements;
|
||||
static CSharedContent m_Instance;
|
||||
};
|
||||
|
@ -134,8 +134,8 @@ private:
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
u32 lastUID;
|
||||
std::string uidSys;
|
||||
u32 m_lastUID;
|
||||
std::string m_uidSys;
|
||||
std::vector<SElement> m_Elements;
|
||||
static cUIDsys m_Instance;
|
||||
};
|
||||
|
|
|
@ -28,8 +28,8 @@ CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii,
|
|||
, m_dataStartAddress(-1)
|
||||
, m_diskHeader(DISKHEADERINFO_ADDRESS)
|
||||
, m_diskHeaderInfo(new SDiskHeaderInfo())
|
||||
, FST_ADDRESS(0)
|
||||
, DOL_ADDRESS(0)
|
||||
, m_fst_address(0)
|
||||
, m_dol_address(0)
|
||||
{
|
||||
m_rootDirectory = ExtractDirectoryName(_rDirectory);
|
||||
|
||||
|
@ -86,14 +86,14 @@ bool CVolumeDirectory::Read(u64 _Offset, u64 _Length, u8* _pBuffer) const
|
|||
WriteToBuffer(APPLOADER_ADDRESS, m_apploader.size(), m_apploader.data(), _Offset, _Length, _pBuffer);
|
||||
}
|
||||
// dol
|
||||
if (_Offset >= DOL_ADDRESS && _Offset < DOL_ADDRESS + m_DOL.size())
|
||||
if (_Offset >= m_dol_address && _Offset < m_dol_address + m_DOL.size())
|
||||
{
|
||||
WriteToBuffer(DOL_ADDRESS, m_DOL.size(), m_DOL.data(), _Offset, _Length, _pBuffer);
|
||||
WriteToBuffer(m_dol_address, m_DOL.size(), m_DOL.data(), _Offset, _Length, _pBuffer);
|
||||
}
|
||||
// fst
|
||||
if (_Offset >= FST_ADDRESS && _Offset < m_dataStartAddress)
|
||||
if (_Offset >= m_fst_address && _Offset < m_dataStartAddress)
|
||||
{
|
||||
WriteToBuffer(FST_ADDRESS, m_FSTData.size(), m_FSTData.data(), _Offset, _Length, _pBuffer);
|
||||
WriteToBuffer(m_fst_address, m_FSTData.size(), m_FSTData.data(), _Offset, _Length, _pBuffer);
|
||||
}
|
||||
|
||||
if (m_virtualDisk.empty())
|
||||
|
@ -279,7 +279,7 @@ bool CVolumeDirectory::SetApploader(const std::string& _rApploader)
|
|||
std::copy(data.begin(), data.end(), m_apploader.begin());
|
||||
|
||||
// 32byte aligned (plus 0x20 padding)
|
||||
DOL_ADDRESS = ROUND_UP(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull);
|
||||
m_dol_address = ROUND_UP(APPLOADER_ADDRESS + m_apploader.size() + 0x20, 0x20ull);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -300,10 +300,10 @@ void CVolumeDirectory::SetDOL(const std::string& rDOL)
|
|||
m_DOL.resize(data.size());
|
||||
std::copy(data.begin(), data.end(), m_DOL.begin());
|
||||
|
||||
Write32((u32)(DOL_ADDRESS >> m_addressShift), 0x0420, &m_diskHeader);
|
||||
Write32((u32)(m_dol_address >> m_addressShift), 0x0420, &m_diskHeader);
|
||||
|
||||
// 32byte aligned (plus 0x20 padding)
|
||||
FST_ADDRESS = ROUND_UP(DOL_ADDRESS + m_DOL.size() + 0x20, 0x20ull);
|
||||
m_fst_address = ROUND_UP(m_dol_address + m_DOL.size() + 0x20, 0x20ull);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,11 +320,11 @@ void CVolumeDirectory::BuildFST()
|
|||
m_FSTData.resize(m_fstNameOffset + m_totalNameSize);
|
||||
|
||||
// if FST hasn't been assigned (ie no apploader/dol setup), set to default
|
||||
if (FST_ADDRESS == 0)
|
||||
FST_ADDRESS = APPLOADER_ADDRESS + 0x2000;
|
||||
if (m_fst_address == 0)
|
||||
m_fst_address = APPLOADER_ADDRESS + 0x2000;
|
||||
|
||||
// 4 byte aligned start of data on disk
|
||||
m_dataStartAddress = ROUND_UP(FST_ADDRESS + m_FSTData.size(), 0x8000ull);
|
||||
m_dataStartAddress = ROUND_UP(m_fst_address + m_FSTData.size(), 0x8000ull);
|
||||
u64 curDataAddress = m_dataStartAddress;
|
||||
|
||||
u32 fstOffset = 0; // Offset within FST data
|
||||
|
@ -343,7 +343,7 @@ void CVolumeDirectory::BuildFST()
|
|||
_dbg_assert_(DVDINTERFACE, nameOffset == m_totalNameSize);
|
||||
|
||||
// write FST size and location
|
||||
Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, &m_diskHeader);
|
||||
Write32((u32)(m_fst_address >> m_addressShift), 0x0424, &m_diskHeader);
|
||||
Write32((u32)(m_FSTData.size() >> m_addressShift), 0x0428, &m_diskHeader);
|
||||
Write32((u32)(m_FSTData.size() >> m_addressShift), 0x042c, &m_diskHeader);
|
||||
}
|
||||
|
|
|
@ -130,6 +130,9 @@ private:
|
|||
std::vector<u8> m_apploader;
|
||||
std::vector<u8> m_DOL;
|
||||
|
||||
u64 m_fst_address;
|
||||
u64 m_dol_address;
|
||||
|
||||
static const u8 ENTRY_SIZE = 0x0c;
|
||||
static const u8 FILE_ENTRY = 0;
|
||||
static const u8 DIRECTORY_ENTRY = 1;
|
||||
|
@ -137,8 +140,6 @@ private:
|
|||
static const u64 DISKHEADERINFO_ADDRESS = 0x440;
|
||||
static const u64 APPLOADER_ADDRESS = 0x2440;
|
||||
static const u32 MAX_NAME_LENGTH = 0x3df;
|
||||
u64 FST_ADDRESS;
|
||||
u64 DOL_ADDRESS;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -19,16 +19,17 @@
|
|||
namespace DiscIO
|
||||
{
|
||||
CVolumeWAD::CVolumeWAD(IBlobReader* _pReader)
|
||||
: m_pReader(_pReader), OpeningBnrOffset(0), hdr_size(0), cert_size(0), tick_size(0), tmd_size(0), data_size(0)
|
||||
: m_pReader(_pReader), m_opening_bnr_offset(0), m_hdr_size(0)
|
||||
, m_cert_size(0), m_tick_size(0), m_tmd_size(0), m_data_size(0)
|
||||
{
|
||||
Read(0x00, 4, (u8*)&hdr_size);
|
||||
Read(0x08, 4, (u8*)&cert_size);
|
||||
Read(0x10, 4, (u8*)&tick_size);
|
||||
Read(0x14, 4, (u8*)&tmd_size);
|
||||
Read(0x18, 4, (u8*)&data_size);
|
||||
Read(0x00, 4, (u8*)&m_hdr_size);
|
||||
Read(0x08, 4, (u8*)&m_cert_size);
|
||||
Read(0x10, 4, (u8*)&m_tick_size);
|
||||
Read(0x14, 4, (u8*)&m_tmd_size);
|
||||
Read(0x18, 4, (u8*)&m_data_size);
|
||||
|
||||
u32 TmdOffset = ALIGN_40(hdr_size) + ALIGN_40(cert_size) + ALIGN_40(tick_size);
|
||||
OpeningBnrOffset = TmdOffset + ALIGN_40(tmd_size) + ALIGN_40(data_size);
|
||||
u32 TmdOffset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size) + ALIGN_40(m_tick_size);
|
||||
m_opening_bnr_offset = TmdOffset + ALIGN_40(m_tmd_size) + ALIGN_40(m_data_size);
|
||||
// read the last digit of the titleID in the ticket
|
||||
Read(TmdOffset + 0x0193, 1, &m_Country);
|
||||
if (m_Country == 2) // SYSMENU
|
||||
|
@ -62,7 +63,7 @@ IVolume::ECountry CVolumeWAD::GetCountry() const
|
|||
std::string CVolumeWAD::GetUniqueID() const
|
||||
{
|
||||
std::string temp = GetMakerID();
|
||||
u32 Offset = ALIGN_40(hdr_size) + ALIGN_40(cert_size);
|
||||
u32 Offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size);
|
||||
|
||||
char GameCode[8];
|
||||
if (!Read(Offset + 0x01E0, 4, (u8*)GameCode))
|
||||
|
@ -77,7 +78,7 @@ std::string CVolumeWAD::GetUniqueID() const
|
|||
|
||||
std::string CVolumeWAD::GetMakerID() const
|
||||
{
|
||||
u32 Offset = ALIGN_40(hdr_size) + ALIGN_40(cert_size) + ALIGN_40(tick_size);
|
||||
u32 Offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size) + ALIGN_40(m_tick_size);
|
||||
|
||||
char temp[3] = {1};
|
||||
// Some weird channels use 0x0000 in place of the MakerID, so we need a check there
|
||||
|
@ -91,7 +92,7 @@ std::string CVolumeWAD::GetMakerID() const
|
|||
|
||||
bool CVolumeWAD::GetTitleID(u8* _pBuffer) const
|
||||
{
|
||||
u32 Offset = ALIGN_40(hdr_size) + ALIGN_40(cert_size);
|
||||
u32 Offset = ALIGN_40(m_hdr_size) + ALIGN_40(m_cert_size);
|
||||
|
||||
if (!Read(Offset + 0x01DC, 8, _pBuffer))
|
||||
return false;
|
||||
|
@ -119,7 +120,7 @@ std::vector<std::string> CVolumeWAD::GetNames() const
|
|||
|
||||
u16 temp[string_length];
|
||||
|
||||
if (footer_size < 0xF1 || !Read(0x9C + (i * bytes_length) + OpeningBnrOffset, bytes_length, (u8*)&temp))
|
||||
if (footer_size < 0xF1 || !Read(0x9C + (i * bytes_length) + m_opening_bnr_offset, bytes_length, (u8*)&temp))
|
||||
{
|
||||
names.push_back("");
|
||||
}
|
||||
|
|
|
@ -39,7 +39,12 @@ public:
|
|||
|
||||
private:
|
||||
std::unique_ptr<IBlobReader> m_pReader;
|
||||
u32 OpeningBnrOffset, hdr_size, cert_size, tick_size, tmd_size, data_size;
|
||||
u32 m_opening_bnr_offset;
|
||||
u32 m_hdr_size;
|
||||
u32 m_cert_size;
|
||||
u32 m_tick_size;
|
||||
u32 m_tmd_size;
|
||||
u32 m_data_size;
|
||||
u8 m_Country;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ CVolumeWiiCrypted::CVolumeWiiCrypted(IBlobReader* _pReader, u64 _VolumeOffset,
|
|||
m_AES_ctx(new aes_context),
|
||||
m_pBuffer(nullptr),
|
||||
m_VolumeOffset(_VolumeOffset),
|
||||
dataOffset(0x20000),
|
||||
m_dataOffset(0x20000),
|
||||
m_LastDecryptedBlockOffset(-1)
|
||||
{
|
||||
aes_setkey_dec(m_AES_ctx.get(), _pVolumeKey, 128);
|
||||
|
@ -66,7 +66,7 @@ bool CVolumeWiiCrypted::Read(u64 _ReadOffset, u64 _Length, u8* _pBuffer) const
|
|||
u64 Offset = _ReadOffset % 0x7C00;
|
||||
|
||||
// read current block
|
||||
if (!m_pReader->Read(m_VolumeOffset + dataOffset + Block * 0x8000, 0x8000, m_pBuffer))
|
||||
if (!m_pReader->Read(m_VolumeOffset + m_dataOffset + Block * 0x8000, 0x8000, m_pBuffer))
|
||||
{
|
||||
return(false);
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ bool CVolumeWiiCrypted::CheckIntegrity() const
|
|||
u32 nClusters = (u32)(partDataSize / 0x8000);
|
||||
for (u32 clusterID = 0; clusterID < nClusters; ++clusterID)
|
||||
{
|
||||
u64 clusterOff = m_VolumeOffset + dataOffset + (u64)clusterID * 0x8000;
|
||||
u64 clusterOff = m_VolumeOffset + m_dataOffset + (u64)clusterID * 0x8000;
|
||||
|
||||
// Read and decrypt the cluster metadata
|
||||
u8 clusterMDCrypted[0x400];
|
||||
|
|
|
@ -47,7 +47,7 @@ private:
|
|||
u8* m_pBuffer;
|
||||
|
||||
u64 m_VolumeOffset;
|
||||
u64 dataOffset;
|
||||
u64 m_dataOffset;
|
||||
|
||||
mutable u64 m_LastDecryptedBlockOffset;
|
||||
mutable unsigned char m_LastDecryptedBlock[0x8000];
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
namespace DiscIO
|
||||
{
|
||||
static const u64 wii_sector_size = 0x8000;
|
||||
static const u64 wii_sector_count = 143432 * 2;
|
||||
static const u64 wii_disc_header_size = 256;
|
||||
static const u64 WII_SECTOR_SIZE = 0x8000;
|
||||
static const u64 WII_SECTOR_COUNT = 143432 * 2;
|
||||
static const u64 WII_DISC_HEADER_SIZE = 256;
|
||||
|
||||
static inline u64 align(u64 value, u64 bounds)
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ WbfsFileReader::WbfsFileReader(const std::string& filename)
|
|||
|
||||
// Grab disc info (assume slot 0, checked in ReadHeader())
|
||||
m_wlba_table = new u16[m_blocks_per_disc];
|
||||
m_files[0]->file.Seek(hd_sector_size + wii_disc_header_size /*+ i * m_disc_info_size*/, SEEK_SET);
|
||||
m_files[0]->file.Seek(m_hd_sector_size + WII_DISC_HEADER_SIZE /*+ i * m_disc_info_size*/, SEEK_SET);
|
||||
m_files[0]->file.ReadBytes(m_wlba_table, m_blocks_per_disc * sizeof(u16));
|
||||
}
|
||||
|
||||
|
@ -83,37 +83,37 @@ bool WbfsFileReader::ReadHeader()
|
|||
m_files[0]->file.Seek(4, SEEK_SET);
|
||||
|
||||
// Read hd size info
|
||||
m_files[0]->file.ReadBytes(&hd_sector_count, 4);
|
||||
hd_sector_count = Common::swap32(hd_sector_count);
|
||||
m_files[0]->file.ReadBytes(&m_hd_sector_count, 4);
|
||||
m_hd_sector_count = Common::swap32(m_hd_sector_count);
|
||||
|
||||
m_files[0]->file.ReadBytes(&hd_sector_shift, 1);
|
||||
hd_sector_size = 1ull << hd_sector_shift;
|
||||
m_files[0]->file.ReadBytes(&m_hd_sector_shift, 1);
|
||||
m_hd_sector_size = 1ull << m_hd_sector_shift;
|
||||
|
||||
if (m_size != hd_sector_count * hd_sector_size)
|
||||
if (m_size != (m_hd_sector_count * m_hd_sector_size))
|
||||
{
|
||||
//printf("File size doesn't match expected size\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read wbfs cluster info
|
||||
m_files[0]->file.ReadBytes(&wbfs_sector_shift, 1);
|
||||
wbfs_sector_size = 1ull << wbfs_sector_shift;
|
||||
wbfs_sector_count = m_size / wbfs_sector_size;
|
||||
m_files[0]->file.ReadBytes(&m_wbfs_sector_shift, 1);
|
||||
m_wbfs_sector_size = 1ull << m_wbfs_sector_shift;
|
||||
m_wbfs_sector_count = m_size / m_wbfs_sector_size;
|
||||
|
||||
if (wbfs_sector_size < wii_sector_size)
|
||||
if (m_wbfs_sector_size < WII_SECTOR_SIZE)
|
||||
{
|
||||
//Setting this too low would case a very large memory allocation
|
||||
return false;
|
||||
}
|
||||
|
||||
m_blocks_per_disc = (wii_sector_count * wii_sector_size) / wbfs_sector_size;
|
||||
m_disc_info_size = align(wii_disc_header_size + m_blocks_per_disc * 2, hd_sector_size);
|
||||
m_blocks_per_disc = (WII_SECTOR_COUNT * WII_SECTOR_SIZE) / m_wbfs_sector_size;
|
||||
m_disc_info_size = align(WII_DISC_HEADER_SIZE + m_blocks_per_disc * 2, m_hd_sector_size);
|
||||
|
||||
// Read disc table
|
||||
m_files[0]->file.Seek(2, SEEK_CUR);
|
||||
m_files[0]->file.ReadBytes(disc_table, 500);
|
||||
m_files[0]->file.ReadBytes(m_disc_table, 500);
|
||||
|
||||
if (0 == disc_table[0])
|
||||
if (0 == m_disc_table[0])
|
||||
{
|
||||
//printf("Game must be in 'slot 0'\n");
|
||||
return false;
|
||||
|
@ -142,11 +142,11 @@ bool WbfsFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
|||
|
||||
File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available)
|
||||
{
|
||||
u64 base_cluster = offset >> wbfs_sector_shift;
|
||||
u64 base_cluster = (offset >> m_wbfs_sector_shift);
|
||||
if (base_cluster < m_blocks_per_disc)
|
||||
{
|
||||
u64 cluster_address = wbfs_sector_size * Common::swap16(m_wlba_table[base_cluster]);
|
||||
u64 cluster_offset = offset & (wbfs_sector_size - 1);
|
||||
u64 cluster_address = m_wbfs_sector_size * Common::swap16(m_wlba_table[base_cluster]);
|
||||
u64 cluster_offset = offset & (m_wbfs_sector_size - 1);
|
||||
u64 final_address = cluster_address + cluster_offset;
|
||||
|
||||
for (u32 i = 0; i != m_total_files; i ++)
|
||||
|
@ -157,7 +157,7 @@ File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available)
|
|||
if (available)
|
||||
{
|
||||
u64 till_end_of_file = m_files[i]->size - (final_address - m_files[i]->base_address);
|
||||
u64 till_end_of_sector = wbfs_sector_size - cluster_offset;
|
||||
u64 till_end_of_sector = m_wbfs_sector_size - cluster_offset;
|
||||
*available = std::min(till_end_of_file, till_end_of_sector);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,14 @@ namespace DiscIO
|
|||
|
||||
class WbfsFileReader : public IBlobReader
|
||||
{
|
||||
public:
|
||||
static WbfsFileReader* Create(const std::string& filename);
|
||||
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
|
||||
|
||||
private:
|
||||
WbfsFileReader(const std::string& filename);
|
||||
~WbfsFileReader();
|
||||
|
||||
|
@ -38,28 +46,21 @@ class WbfsFileReader : public IBlobReader
|
|||
u32 m_total_files;
|
||||
u64 m_size;
|
||||
|
||||
u64 hd_sector_size;
|
||||
u8 hd_sector_shift;
|
||||
u32 hd_sector_count;
|
||||
u64 m_hd_sector_size;
|
||||
u8 m_hd_sector_shift;
|
||||
u32 m_hd_sector_count;
|
||||
|
||||
u64 wbfs_sector_size;
|
||||
u8 wbfs_sector_shift;
|
||||
u64 wbfs_sector_count;
|
||||
u64 m_wbfs_sector_size;
|
||||
u8 m_wbfs_sector_shift;
|
||||
u64 m_wbfs_sector_count;
|
||||
u64 m_disc_info_size;
|
||||
|
||||
u8 disc_table[500];
|
||||
u8 m_disc_table[500];
|
||||
|
||||
u16* m_wlba_table;
|
||||
u64 m_blocks_per_disc;
|
||||
|
||||
bool m_good;
|
||||
|
||||
public:
|
||||
static WbfsFileReader* Create(const std::string& filename);
|
||||
|
||||
u64 GetDataSize() const override { return m_size; }
|
||||
u64 GetRawSize() const override { return m_size; }
|
||||
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
|
||||
};
|
||||
|
||||
bool IsWbfsBlob(const std::string& filename);
|
||||
|
|
Loading…
Reference in New Issue