Only open file once when detecting blob type
This commit is contained in:
parent
3fdcbbdd92
commit
d1ea00ed88
|
@ -177,23 +177,31 @@ std::unique_ptr<IBlobReader> CreateBlobReader(const std::string& filename)
|
||||||
if (cdio_is_cdrom(filename))
|
if (cdio_is_cdrom(filename))
|
||||||
return DriveReader::Create(filename);
|
return DriveReader::Create(filename);
|
||||||
|
|
||||||
if (!File::Exists(filename))
|
File::IOFile file(filename, "rb");
|
||||||
|
u32 magic;
|
||||||
|
if (!file.ReadArray(&magic, 1))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (IsWbfsBlob(filename))
|
// Conveniently, every supported file format (except for plain disc images) starts
|
||||||
return WbfsFileReader::Create(filename);
|
// with a 4-byte magic number that identifies the format, so we just need a simple
|
||||||
|
// switch statement to create the right blob type. If the magic number doesn't
|
||||||
|
// match any known magic number, we assume it's a plain disc image. If that
|
||||||
|
// assumption is wrong, the volume code that runs later will notice the error
|
||||||
|
// because the blob won't provide valid data when reading the GC/Wii disc header.
|
||||||
|
|
||||||
if (IsGCZBlob(filename))
|
switch (magic)
|
||||||
return CompressedBlobReader::Create(filename);
|
{
|
||||||
|
case CISO_MAGIC:
|
||||||
if (IsCISOBlob(filename))
|
|
||||||
return CISOFileReader::Create(filename);
|
return CISOFileReader::Create(filename);
|
||||||
|
case GCZ_MAGIC:
|
||||||
if (IsTGCBlob(filename))
|
return CompressedBlobReader::Create(filename);
|
||||||
|
case TGC_MAGIC:
|
||||||
return TGCFileReader::Create(filename);
|
return TGCFileReader::Create(filename);
|
||||||
|
case WBFS_MAGIC:
|
||||||
// Still here? Assume plain file - since we know it exists due to the File::Exists check above.
|
return WbfsFileReader::Create(filename);
|
||||||
return PlainFileReader::Create(filename);
|
default:
|
||||||
|
return PlainFileReader::Create(filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
static const char CISO_MAGIC[] = "CISO";
|
|
||||||
|
|
||||||
CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file)
|
CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file)
|
||||||
{
|
{
|
||||||
m_size = m_file.GetSize();
|
m_size = m_file.GetSize();
|
||||||
|
@ -30,11 +28,10 @@ CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file)
|
||||||
|
|
||||||
std::unique_ptr<CISOFileReader> CISOFileReader::Create(const std::string& filename)
|
std::unique_ptr<CISOFileReader> CISOFileReader::Create(const std::string& filename)
|
||||||
{
|
{
|
||||||
if (IsCISOBlob(filename))
|
File::IOFile f(filename, "rb");
|
||||||
{
|
CISOHeader header;
|
||||||
File::IOFile f(filename, "rb");
|
if (f.ReadArray(&header, 1) && header.magic == CISO_MAGIC)
|
||||||
return std::unique_ptr<CISOFileReader>(new CISOFileReader(f.ReleaseHandle()));
|
return std::unique_ptr<CISOFileReader>(new CISOFileReader(f.ReleaseHandle()));
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -81,13 +78,4 @@ bool CISOFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsCISOBlob(const std::string& filename)
|
|
||||||
{
|
|
||||||
File::IOFile f(filename, "rb");
|
|
||||||
|
|
||||||
CISOHeader header;
|
|
||||||
return (f.ReadArray(&header, 1) &&
|
|
||||||
std::equal(header.magic, header.magic + sizeof(header.magic), CISO_MAGIC));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
bool IsCISOBlob(const std::string& filename);
|
static constexpr u32 CISO_MAGIC = 0x4F534943; // "CISO" (byteswapped to little endian)
|
||||||
|
|
||||||
static const u32 CISO_HEADER_SIZE = 0x8000;
|
static const u32 CISO_HEADER_SIZE = 0x8000;
|
||||||
static const u32 CISO_MAP_SIZE = CISO_HEADER_SIZE - sizeof(u32) - sizeof(char) * 4;
|
static const u32 CISO_MAP_SIZE = CISO_HEADER_SIZE - sizeof(u32) - sizeof(char) * 4;
|
||||||
|
@ -22,7 +22,7 @@ static const u32 CISO_MAP_SIZE = CISO_HEADER_SIZE - sizeof(u32) - sizeof(char) *
|
||||||
struct CISOHeader
|
struct CISOHeader
|
||||||
{
|
{
|
||||||
// "CISO"
|
// "CISO"
|
||||||
char magic[4];
|
u32 magic;
|
||||||
|
|
||||||
// little endian
|
// little endian
|
||||||
u32 block_size;
|
u32 block_size;
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
|
bool IsGCZBlob(const std::string& filename);
|
||||||
|
|
||||||
CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file_name(filename)
|
CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file_name(filename)
|
||||||
{
|
{
|
||||||
m_file.Open(filename, "rb");
|
m_file.Open(filename, "rb");
|
||||||
|
@ -192,7 +194,7 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u
|
||||||
callback(GetStringT("Files opened, ready to compress."), 0, arg);
|
callback(GetStringT("Files opened, ready to compress."), 0, arg);
|
||||||
|
|
||||||
CompressedBlobHeader header;
|
CompressedBlobHeader header;
|
||||||
header.magic_cookie = kBlobCookie;
|
header.magic_cookie = GCZ_MAGIC;
|
||||||
header.sub_type = sub_type;
|
header.sub_type = sub_type;
|
||||||
header.block_size = block_size;
|
header.block_size = block_size;
|
||||||
header.data_size = File::GetSize(infile);
|
header.data_size = File::GetSize(infile);
|
||||||
|
@ -401,7 +403,7 @@ bool IsGCZBlob(const std::string& filename)
|
||||||
File::IOFile f(filename, "rb");
|
File::IOFile f(filename, "rb");
|
||||||
|
|
||||||
CompressedBlobHeader header;
|
CompressedBlobHeader header;
|
||||||
return f.ReadArray(&header, 1) && (header.magic_cookie == kBlobCookie);
|
return f.ReadArray(&header, 1) && (header.magic_cookie == GCZ_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -23,9 +23,7 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
bool IsGCZBlob(const std::string& filename);
|
static constexpr u32 GCZ_MAGIC = 0xB10BC001;
|
||||||
|
|
||||||
const u32 kBlobCookie = 0xB10BC001;
|
|
||||||
|
|
||||||
// GCZ file structure:
|
// GCZ file structure:
|
||||||
// BlobHeader
|
// BlobHeader
|
||||||
|
|
|
@ -56,21 +56,12 @@ void Replace32(u64 offset, u64 nbytes, u8* out_ptr, u64 replace_offset, u32 repl
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
bool IsTGCBlob(const std::string& path)
|
|
||||||
{
|
|
||||||
File::IOFile file(path, "rb");
|
|
||||||
|
|
||||||
TGCHeader header;
|
|
||||||
return (file.ReadArray(&header, 1) && header.magic == Common::swap32(0xAE0F38A2));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<TGCFileReader> TGCFileReader::Create(const std::string& path)
|
std::unique_ptr<TGCFileReader> TGCFileReader::Create(const std::string& path)
|
||||||
{
|
{
|
||||||
if (IsTGCBlob(path))
|
File::IOFile file(path, "rb");
|
||||||
{
|
TGCHeader header;
|
||||||
File::IOFile file(path, "rb");
|
if (file.ReadArray(&header, 1) && header.magic == TGC_MAGIC)
|
||||||
return std::unique_ptr<TGCFileReader>(new TGCFileReader(std::move(file)));
|
return std::unique_ptr<TGCFileReader>(new TGCFileReader(std::move(file)));
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
bool IsTGCBlob(const std::string& path);
|
static constexpr u32 TGC_MAGIC = 0xA2380FAE;
|
||||||
|
|
||||||
struct TGCHeader
|
struct TGCHeader
|
||||||
{
|
{
|
||||||
|
|
|
@ -83,8 +83,10 @@ bool WbfsFileReader::ReadHeader()
|
||||||
{
|
{
|
||||||
// Read hd size info
|
// Read hd size info
|
||||||
m_files[0]->file.ReadBytes(&m_header, sizeof(WbfsHeader));
|
m_files[0]->file.ReadBytes(&m_header, sizeof(WbfsHeader));
|
||||||
m_header.hd_sector_count = Common::swap32(m_header.hd_sector_count);
|
if (m_header.magic != WBFS_MAGIC)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_header.hd_sector_count = Common::swap32(m_header.hd_sector_count);
|
||||||
m_hd_sector_size = 1ull << m_header.hd_sector_shift;
|
m_hd_sector_size = 1ull << m_header.hd_sector_shift;
|
||||||
|
|
||||||
if (m_size != (m_header.hd_sector_count * m_hd_sector_size))
|
if (m_size != (m_header.hd_sector_count * m_hd_sector_size))
|
||||||
|
@ -172,14 +174,4 @@ std::unique_ptr<WbfsFileReader> WbfsFileReader::Create(const std::string& filena
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsWbfsBlob(const std::string& filename)
|
|
||||||
{
|
|
||||||
File::IOFile f(filename, "rb");
|
|
||||||
|
|
||||||
u8 magic[4] = {0, 0, 0, 0};
|
|
||||||
f.ReadBytes(&magic, 4);
|
|
||||||
|
|
||||||
return (magic[0] == 'W') && (magic[1] == 'B') && (magic[2] == 'F') && (magic[3] == 'S');
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
|
static constexpr u32 WBFS_MAGIC = 0x53464257; // "WBFS" (byteswapped to little endian)
|
||||||
|
|
||||||
class WbfsFileReader : public IBlobReader
|
class WbfsFileReader : public IBlobReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -58,7 +60,7 @@ private:
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct WbfsHeader
|
struct WbfsHeader
|
||||||
{
|
{
|
||||||
char magic[4];
|
u32 magic;
|
||||||
u32 hd_sector_count;
|
u32 hd_sector_count;
|
||||||
u8 hd_sector_shift;
|
u8 hd_sector_shift;
|
||||||
u8 wbfs_sector_shift;
|
u8 wbfs_sector_shift;
|
||||||
|
@ -73,6 +75,4 @@ private:
|
||||||
bool m_good;
|
bool m_good;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsWbfsBlob(const std::string& filename);
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue