Only open file once when detecting blob type

This commit is contained in:
JosJuice 2016-12-21 11:30:12 +01:00
parent 3fdcbbdd92
commit d1ea00ed88
9 changed files with 40 additions and 61 deletions

View File

@ -177,23 +177,31 @@ std::unique_ptr<IBlobReader> CreateBlobReader(const std::string& filename)
if (cdio_is_cdrom(filename))
return DriveReader::Create(filename);
if (!File::Exists(filename))
File::IOFile file(filename, "rb");
u32 magic;
if (!file.ReadArray(&magic, 1))
return nullptr;
if (IsWbfsBlob(filename))
return WbfsFileReader::Create(filename);
// Conveniently, every supported file format (except for plain disc images) starts
// 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))
return CompressedBlobReader::Create(filename);
if (IsCISOBlob(filename))
switch (magic)
{
case CISO_MAGIC:
return CISOFileReader::Create(filename);
if (IsTGCBlob(filename))
case GCZ_MAGIC:
return CompressedBlobReader::Create(filename);
case TGC_MAGIC:
return TGCFileReader::Create(filename);
// Still here? Assume plain file - since we know it exists due to the File::Exists check above.
return PlainFileReader::Create(filename);
case WBFS_MAGIC:
return WbfsFileReader::Create(filename);
default:
return PlainFileReader::Create(filename);
}
}
} // namespace

View File

@ -12,8 +12,6 @@
namespace DiscIO
{
static const char CISO_MAGIC[] = "CISO";
CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file)
{
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)
{
if (IsCISOBlob(filename))
{
File::IOFile f(filename, "rb");
File::IOFile f(filename, "rb");
CISOHeader header;
if (f.ReadArray(&header, 1) && header.magic == CISO_MAGIC)
return std::unique_ptr<CISOFileReader>(new CISOFileReader(f.ReleaseHandle()));
}
return nullptr;
}
@ -81,13 +78,4 @@ bool CISOFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
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

View File

@ -14,7 +14,7 @@
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_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
{
// "CISO"
char magic[4];
u32 magic;
// little endian
u32 block_size;

View File

@ -28,6 +28,8 @@
namespace DiscIO
{
bool IsGCZBlob(const std::string& filename);
CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file_name(filename)
{
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);
CompressedBlobHeader header;
header.magic_cookie = kBlobCookie;
header.magic_cookie = GCZ_MAGIC;
header.sub_type = sub_type;
header.block_size = block_size;
header.data_size = File::GetSize(infile);
@ -401,7 +403,7 @@ bool IsGCZBlob(const std::string& filename)
File::IOFile f(filename, "rb");
CompressedBlobHeader header;
return f.ReadArray(&header, 1) && (header.magic_cookie == kBlobCookie);
return f.ReadArray(&header, 1) && (header.magic_cookie == GCZ_MAGIC);
}
} // namespace

View File

@ -23,9 +23,7 @@
namespace DiscIO
{
bool IsGCZBlob(const std::string& filename);
const u32 kBlobCookie = 0xB10BC001;
static constexpr u32 GCZ_MAGIC = 0xB10BC001;
// GCZ file structure:
// BlobHeader

View File

@ -56,21 +56,12 @@ void Replace32(u64 offset, u64 nbytes, u8* out_ptr, u64 replace_offset, u32 repl
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)
{
if (IsTGCBlob(path))
{
File::IOFile file(path, "rb");
File::IOFile file(path, "rb");
TGCHeader header;
if (file.ReadArray(&header, 1) && header.magic == TGC_MAGIC)
return std::unique_ptr<TGCFileReader>(new TGCFileReader(std::move(file)));
}
return nullptr;
}

View File

@ -14,7 +14,7 @@
namespace DiscIO
{
bool IsTGCBlob(const std::string& path);
static constexpr u32 TGC_MAGIC = 0xA2380FAE;
struct TGCHeader
{

View File

@ -83,8 +83,10 @@ bool WbfsFileReader::ReadHeader()
{
// Read hd size info
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;
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;
}
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

View File

@ -14,6 +14,8 @@
namespace DiscIO
{
static constexpr u32 WBFS_MAGIC = 0x53464257; // "WBFS" (byteswapped to little endian)
class WbfsFileReader : public IBlobReader
{
public:
@ -58,7 +60,7 @@ private:
#pragma pack(1)
struct WbfsHeader
{
char magic[4];
u32 magic;
u32 hd_sector_count;
u8 hd_sector_shift;
u8 wbfs_sector_shift;
@ -73,6 +75,4 @@ private:
bool m_good;
};
bool IsWbfsBlob(const std::string& filename);
} // namespace