From d1ea00ed884cf714a252d3194d3f8dbdc54ac937 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 21 Dec 2016 11:30:12 +0100 Subject: [PATCH 1/5] Only open file once when detecting blob type --- Source/Core/DiscIO/Blob.cpp | 32 +++++++++++++++++---------- Source/Core/DiscIO/CISOBlob.cpp | 18 +++------------ Source/Core/DiscIO/CISOBlob.h | 4 ++-- Source/Core/DiscIO/CompressedBlob.cpp | 6 +++-- Source/Core/DiscIO/CompressedBlob.h | 4 +--- Source/Core/DiscIO/TGCBlob.cpp | 15 +++---------- Source/Core/DiscIO/TGCBlob.h | 2 +- Source/Core/DiscIO/WbfsBlob.cpp | 14 +++--------- Source/Core/DiscIO/WbfsBlob.h | 6 ++--- 9 files changed, 40 insertions(+), 61 deletions(-) diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index d7aad9332a..d1dd0e7c1e 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -177,23 +177,31 @@ std::unique_ptr 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 diff --git a/Source/Core/DiscIO/CISOBlob.cpp b/Source/Core/DiscIO/CISOBlob.cpp index 37e427793b..388fd71d60 100644 --- a/Source/Core/DiscIO/CISOBlob.cpp +++ b/Source/Core/DiscIO/CISOBlob.cpp @@ -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::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(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 diff --git a/Source/Core/DiscIO/CISOBlob.h b/Source/Core/DiscIO/CISOBlob.h index 9eed0d992a..33791bab18 100644 --- a/Source/Core/DiscIO/CISOBlob.h +++ b/Source/Core/DiscIO/CISOBlob.h @@ -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; diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp index 680ca8d179..4a749a7ebe 100644 --- a/Source/Core/DiscIO/CompressedBlob.cpp +++ b/Source/Core/DiscIO/CompressedBlob.cpp @@ -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 diff --git a/Source/Core/DiscIO/CompressedBlob.h b/Source/Core/DiscIO/CompressedBlob.h index 4c33cf85be..7769a9d8cd 100644 --- a/Source/Core/DiscIO/CompressedBlob.h +++ b/Source/Core/DiscIO/CompressedBlob.h @@ -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 diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index 85a5a854aa..04ef3a1a9d 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -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::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(new TGCFileReader(std::move(file))); - } return nullptr; } diff --git a/Source/Core/DiscIO/TGCBlob.h b/Source/Core/DiscIO/TGCBlob.h index c1057afc27..62fd0cd759 100644 --- a/Source/Core/DiscIO/TGCBlob.h +++ b/Source/Core/DiscIO/TGCBlob.h @@ -14,7 +14,7 @@ namespace DiscIO { -bool IsTGCBlob(const std::string& path); +static constexpr u32 TGC_MAGIC = 0xA2380FAE; struct TGCHeader { diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index 6acbe5d0b3..58ec6fc4c7 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -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::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 diff --git a/Source/Core/DiscIO/WbfsBlob.h b/Source/Core/DiscIO/WbfsBlob.h index b7b2323950..5012ccd174 100644 --- a/Source/Core/DiscIO/WbfsBlob.h +++ b/Source/Core/DiscIO/WbfsBlob.h @@ -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 From 8d54bbc52803a2e665e58a8a9b1b22182c7f0027 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 21 Dec 2016 12:50:15 +0100 Subject: [PATCH 2/5] Don't create new IOFiles when creating a blob ...except for WBFS, which is special because it has the ability to open multiple files. --- Source/Core/DiscIO/Blob.cpp | 9 ++- Source/Core/DiscIO/Blob.h | 6 +- Source/Core/DiscIO/CISOBlob.cpp | 11 +-- Source/Core/DiscIO/CISOBlob.h | 4 +- Source/Core/DiscIO/CompressedBlob.cpp | 108 ++++++++++++++------------ Source/Core/DiscIO/CompressedBlob.h | 5 +- Source/Core/DiscIO/FileBlob.cpp | 13 ++-- Source/Core/DiscIO/FileBlob.h | 4 +- Source/Core/DiscIO/TGCBlob.cpp | 9 ++- Source/Core/DiscIO/TGCBlob.h | 4 +- 10 files changed, 93 insertions(+), 80 deletions(-) diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index d1dd0e7c1e..e40b530233 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "Common/CDUtils.h" #include "Common/CommonTypes.h" @@ -192,15 +193,15 @@ std::unique_ptr CreateBlobReader(const std::string& filename) switch (magic) { case CISO_MAGIC: - return CISOFileReader::Create(filename); + return CISOFileReader::Create(std::move(file)); case GCZ_MAGIC: - return CompressedBlobReader::Create(filename); + return CompressedBlobReader::Create(std::move(file), filename); case TGC_MAGIC: - return TGCFileReader::Create(filename); + return TGCFileReader::Create(std::move(file)); case WBFS_MAGIC: return WbfsFileReader::Create(filename); default: - return PlainFileReader::Create(filename); + return PlainFileReader::Create(std::move(file)); } } diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h index fa068c33ef..7f954cd65b 100644 --- a/Source/Core/DiscIO/Blob.h +++ b/Source/Core/DiscIO/Blob.h @@ -159,10 +159,10 @@ std::unique_ptr CreateBlobReader(const std::string& filename); typedef bool (*CompressCB)(const std::string& text, float percent, void* arg); -bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type = 0, - int sector_size = 16384, CompressCB callback = nullptr, +bool CompressFileToBlob(const std::string& infile_path, const std::string& outfile_path, + u32 sub_type = 0, int sector_size = 16384, CompressCB callback = nullptr, void* arg = nullptr); -bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, +bool DecompressBlobToFile(const std::string& infile_path, const std::string& outfile_path, CompressCB callback = nullptr, void* arg = nullptr); } // namespace diff --git a/Source/Core/DiscIO/CISOBlob.cpp b/Source/Core/DiscIO/CISOBlob.cpp index 388fd71d60..846952ce8a 100644 --- a/Source/Core/DiscIO/CISOBlob.cpp +++ b/Source/Core/DiscIO/CISOBlob.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "Common/CommonTypes.h" #include "Common/FileUtil.h" @@ -12,11 +13,12 @@ namespace DiscIO { -CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file) +CISOFileReader::CISOFileReader(File::IOFile file) : m_file(std::move(file)) { m_size = m_file.GetSize(); CISOHeader header; + m_file.Seek(0, SEEK_SET); m_file.ReadArray(&header, 1); m_block_size = header.block_size; @@ -26,12 +28,11 @@ CISOFileReader::CISOFileReader(std::FILE* file) : m_file(file) m_ciso_map[idx] = (1 == header.map[idx]) ? count++ : UNUSED_BLOCK_ID; } -std::unique_ptr CISOFileReader::Create(const std::string& filename) +std::unique_ptr CISOFileReader::Create(File::IOFile file) { - File::IOFile f(filename, "rb"); CISOHeader header; - if (f.ReadArray(&header, 1) && header.magic == CISO_MAGIC) - return std::unique_ptr(new CISOFileReader(f.ReleaseHandle())); + if (file.Seek(0, SEEK_SET) && file.ReadArray(&header, 1) && header.magic == CISO_MAGIC) + return std::unique_ptr(new CISOFileReader(std::move(file))); return nullptr; } diff --git a/Source/Core/DiscIO/CISOBlob.h b/Source/Core/DiscIO/CISOBlob.h index 33791bab18..b8c0ebd816 100644 --- a/Source/Core/DiscIO/CISOBlob.h +++ b/Source/Core/DiscIO/CISOBlob.h @@ -34,7 +34,7 @@ struct CISOHeader class CISOFileReader : public IBlobReader { public: - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(File::IOFile file); BlobType GetBlobType() const override { return BlobType::CISO; } // The CISO format does not save the original file size. @@ -45,7 +45,7 @@ public: bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - CISOFileReader(std::FILE* file); + CISOFileReader(File::IOFile file); typedef u16 MapType; static const MapType UNUSED_BLOCK_ID = -1; diff --git a/Source/Core/DiscIO/CompressedBlob.cpp b/Source/Core/DiscIO/CompressedBlob.cpp index 4a749a7ebe..0cf8dbc5b3 100644 --- a/Source/Core/DiscIO/CompressedBlob.cpp +++ b/Source/Core/DiscIO/CompressedBlob.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -28,12 +29,13 @@ namespace DiscIO { -bool IsGCZBlob(const std::string& filename); +bool IsGCZBlob(File::IOFile& file); -CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file_name(filename) +CompressedBlobReader::CompressedBlobReader(File::IOFile file, const std::string& filename) + : m_file(std::move(file)), m_file_name(filename) { - m_file.Open(filename, "rb"); - m_file_size = File::GetSize(filename); + m_file_size = m_file.GetSize(); + m_file.Seek(0, SEEK_SET); m_file.ReadArray(&m_header, 1); SetSectorSize(m_header.block_size); @@ -55,10 +57,12 @@ CompressedBlobReader::CompressedBlobReader(const std::string& filename) : m_file m_zlib_buffer.resize(zlib_buffer_size); } -std::unique_ptr CompressedBlobReader::Create(const std::string& filename) +std::unique_ptr CompressedBlobReader::Create(File::IOFile file, + const std::string& filename) { - if (IsGCZBlob(filename)) - return std::unique_ptr(new CompressedBlobReader(filename)); + if (IsGCZBlob(file)) + return std::unique_ptr( + new CompressedBlobReader(std::move(file), filename)); return nullptr; } @@ -147,40 +151,41 @@ bool CompressedBlobReader::GetBlock(u64 block_num, u8* out_ptr) return true; } -bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u32 sub_type, - int block_size, CompressCB callback, void* arg) +bool CompressFileToBlob(const std::string& infile_path, const std::string& outfile_path, + u32 sub_type, int block_size, CompressCB callback, void* arg) { bool scrubbing = false; + File::IOFile infile(infile_path, "rb"); if (IsGCZBlob(infile)) { - PanicAlertT("\"%s\" is already compressed! Cannot compress it further.", infile.c_str()); + PanicAlertT("\"%s\" is already compressed! Cannot compress it further.", infile_path.c_str()); return false; } - File::IOFile inf(infile, "rb"); - if (!inf) + if (!infile) { - PanicAlertT("Failed to open the input file \"%s\".", infile.c_str()); + PanicAlertT("Failed to open the input file \"%s\".", infile_path.c_str()); return false; } - File::IOFile f(outfile, "wb"); - if (!f) + File::IOFile outfile(outfile_path, "wb"); + if (!outfile) { PanicAlertT("Failed to open the output file \"%s\".\n" "Check that you have permissions to write the target folder and that the media can " "be written.", - outfile.c_str()); + outfile_path.c_str()); return false; } DiscScrubber disc_scrubber; if (sub_type == 1) { - if (!disc_scrubber.SetupScrub(infile, block_size)) + if (!disc_scrubber.SetupScrub(infile_path, block_size)) { - PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.", infile.c_str()); + PanicAlertT("\"%s\" failed to be scrubbed. Probably the image is corrupt.", + infile_path.c_str()); return false; } @@ -197,7 +202,7 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u header.magic_cookie = GCZ_MAGIC; header.sub_type = sub_type; header.block_size = block_size; - header.data_size = File::GetSize(infile); + header.data_size = infile.GetSize(); // round upwards! header.num_blocks = (u32)((header.data_size + (block_size - 1)) / block_size); @@ -208,9 +213,9 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u std::vector in_buf(block_size); // seek past the header (we will write it at the end) - f.Seek(sizeof(CompressedBlobHeader), SEEK_CUR); + outfile.Seek(sizeof(CompressedBlobHeader), SEEK_CUR); // seek past the offset and hash tables (we will write them at the end) - f.Seek((sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR); + outfile.Seek((sizeof(u64) + sizeof(u32)) * header.num_blocks, SEEK_CUR); // Now we are ready to write compressed data! u64 position = 0; @@ -223,7 +228,7 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u { if (i % progress_monitor == 0) { - const u64 inpos = inf.Tell(); + const u64 inpos = infile.Tell(); int ratio = 0; if (inpos != 0) ratio = (int)(100 * position / inpos); @@ -243,9 +248,9 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u size_t read_bytes; if (scrubbing) - read_bytes = disc_scrubber.GetNextBlock(inf, in_buf.data()); + read_bytes = disc_scrubber.GetNextBlock(infile, in_buf.data()); else - inf.ReadArray(in_buf.data(), header.block_size, &read_bytes); + infile.ReadArray(in_buf.data(), header.block_size, &read_bytes); if (read_bytes < header.block_size) std::fill(in_buf.begin() + read_bytes, in_buf.begin() + header.block_size, 0); @@ -285,11 +290,11 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u num_compressed++; } - if (!f.WriteBytes(write_buf, write_size)) + if (!outfile.WriteBytes(write_buf, write_size)) { PanicAlertT("Failed to write the output file \"%s\".\n" "Check that you have enough space available on the target drive.", - outfile.c_str()); + outfile_path.c_str()); success = false; break; } @@ -304,16 +309,16 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u if (!success) { // Remove the incomplete output file. - f.Close(); - File::Delete(outfile); + outfile.Close(); + File::Delete(outfile_path); } else { // Okay, go back and fill in headers - f.Seek(0, SEEK_SET); - f.WriteArray(&header, 1); - f.WriteArray(offsets.data(), header.num_blocks); - f.WriteArray(hashes.data(), header.num_blocks); + outfile.Seek(0, SEEK_SET); + outfile.WriteArray(&header, 1); + outfile.WriteArray(offsets.data(), header.num_blocks); + outfile.WriteArray(hashes.data(), header.num_blocks); } // Cleanup @@ -326,29 +331,34 @@ bool CompressFileToBlob(const std::string& infile, const std::string& outfile, u return success; } -bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, +bool DecompressBlobToFile(const std::string& infile_path, const std::string& outfile_path, CompressCB callback, void* arg) { - if (!IsGCZBlob(infile)) + std::unique_ptr reader; { - PanicAlertT("File not compressed"); - return false; + File::IOFile infile(infile_path, "rb"); + if (!IsGCZBlob(infile)) + { + PanicAlertT("File not compressed"); + return false; + } + + reader = CompressedBlobReader::Create(std::move(infile), infile_path); } - std::unique_ptr reader(CompressedBlobReader::Create(infile)); if (!reader) { - PanicAlertT("Failed to open the input file \"%s\".", infile.c_str()); + PanicAlertT("Failed to open the input file \"%s\".", infile_path.c_str()); return false; } - File::IOFile f(outfile, "wb"); - if (!f) + File::IOFile outfile(outfile_path, "wb"); + if (!outfile) { PanicAlertT("Failed to open the output file \"%s\".\n" "Check that you have permissions to write the target folder and that the media can " "be written.", - outfile.c_str()); + outfile_path.c_str()); return false; } @@ -374,11 +384,11 @@ bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, } const size_t sz = i == num_buffers - 1 ? last_buffer_size : buffer_size; reader->Read(i * buffer_size, sz, buffer.data()); - if (!f.WriteBytes(buffer.data(), sz)) + if (!outfile.WriteBytes(buffer.data(), sz)) { PanicAlertT("Failed to write the output file \"%s\".\n" "Check that you have enough space available on the target drive.", - outfile.c_str()); + outfile_path.c_str()); success = false; break; } @@ -387,23 +397,21 @@ bool DecompressBlobToFile(const std::string& infile, const std::string& outfile, if (!success) { // Remove the incomplete output file. - f.Close(); - File::Delete(outfile); + outfile.Close(); + File::Delete(outfile_path); } else { - f.Resize(header.data_size); + outfile.Resize(header.data_size); } return true; } -bool IsGCZBlob(const std::string& filename) +bool IsGCZBlob(File::IOFile& file) { - File::IOFile f(filename, "rb"); - CompressedBlobHeader header; - return f.ReadArray(&header, 1) && (header.magic_cookie == GCZ_MAGIC); + return file.Seek(0, SEEK_SET) && file.ReadArray(&header, 1) && header.magic_cookie == GCZ_MAGIC; } } // namespace diff --git a/Source/Core/DiscIO/CompressedBlob.h b/Source/Core/DiscIO/CompressedBlob.h index 7769a9d8cd..281db6c64a 100644 --- a/Source/Core/DiscIO/CompressedBlob.h +++ b/Source/Core/DiscIO/CompressedBlob.h @@ -44,7 +44,8 @@ struct CompressedBlobHeader // 32 bytes class CompressedBlobReader : public SectorReader { public: - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(File::IOFile file, + const std::string& filename); ~CompressedBlobReader(); const CompressedBlobHeader& GetHeader() const { return m_header; } BlobType GetBlobType() const override { return BlobType::GCZ; } @@ -54,7 +55,7 @@ public: bool GetBlock(u64 block_num, u8* out_ptr) override; private: - CompressedBlobReader(const std::string& filename); + CompressedBlobReader(File::IOFile file, const std::string& filename); CompressedBlobHeader m_header; std::vector m_block_pointers; diff --git a/Source/Core/DiscIO/FileBlob.cpp b/Source/Core/DiscIO/FileBlob.cpp index 7d1dabe198..3547ef658d 100644 --- a/Source/Core/DiscIO/FileBlob.cpp +++ b/Source/Core/DiscIO/FileBlob.cpp @@ -2,22 +2,23 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include "DiscIO/FileBlob.h" #include #include +#include + +#include "DiscIO/FileBlob.h" namespace DiscIO { -PlainFileReader::PlainFileReader(std::FILE* file) : m_file(file) +PlainFileReader::PlainFileReader(File::IOFile file) : m_file(std::move(file)) { m_size = m_file.GetSize(); } -std::unique_ptr PlainFileReader::Create(const std::string& filename) +std::unique_ptr PlainFileReader::Create(File::IOFile file) { - File::IOFile f(filename, "rb"); - if (f) - return std::unique_ptr(new PlainFileReader(f.ReleaseHandle())); + if (file) + return std::unique_ptr(new PlainFileReader(std::move(file))); return nullptr; } diff --git a/Source/Core/DiscIO/FileBlob.h b/Source/Core/DiscIO/FileBlob.h index 3a85799651..22cd614ec6 100644 --- a/Source/Core/DiscIO/FileBlob.h +++ b/Source/Core/DiscIO/FileBlob.h @@ -17,7 +17,7 @@ namespace DiscIO class PlainFileReader : public IBlobReader { public: - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(File::IOFile file); BlobType GetBlobType() const override { return BlobType::PLAIN; } u64 GetDataSize() const override { return m_size; } @@ -25,7 +25,7 @@ public: bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - PlainFileReader(std::FILE* file); + PlainFileReader(File::IOFile file); File::IOFile m_file; s64 m_size; diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp index 04ef3a1a9d..886bbb6a78 100644 --- a/Source/Core/DiscIO/TGCBlob.cpp +++ b/Source/Core/DiscIO/TGCBlob.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "Common/CommonFuncs.h" #include "Common/FileUtil.h" @@ -56,18 +57,18 @@ void Replace32(u64 offset, u64 nbytes, u8* out_ptr, u64 replace_offset, u32 repl namespace DiscIO { -std::unique_ptr TGCFileReader::Create(const std::string& path) +std::unique_ptr TGCFileReader::Create(File::IOFile file) { - File::IOFile file(path, "rb"); TGCHeader header; - if (file.ReadArray(&header, 1) && header.magic == TGC_MAGIC) + if (file.Seek(0, SEEK_SET) && file.ReadArray(&header, 1) && header.magic == TGC_MAGIC) return std::unique_ptr(new TGCFileReader(std::move(file))); return nullptr; } -TGCFileReader::TGCFileReader(File::IOFile&& file) : m_file(std::move(file)) +TGCFileReader::TGCFileReader(File::IOFile file) : m_file(std::move(file)) { + m_file.Seek(0, SEEK_SET); m_file.ReadArray(&m_header, 1); u32 header_size = Common::swap32(m_header.header_size); m_size = m_file.GetSize(); diff --git a/Source/Core/DiscIO/TGCBlob.h b/Source/Core/DiscIO/TGCBlob.h index 62fd0cd759..86c0a85033 100644 --- a/Source/Core/DiscIO/TGCBlob.h +++ b/Source/Core/DiscIO/TGCBlob.h @@ -40,7 +40,7 @@ struct TGCHeader class TGCFileReader final : public IBlobReader { public: - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(File::IOFile file); BlobType GetBlobType() const override { return BlobType::TGC; } u64 GetDataSize() const override; @@ -48,7 +48,7 @@ public: bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - TGCFileReader(File::IOFile&& file); + TGCFileReader(File::IOFile file); bool InternalRead(u64 offset, u64 nbytes, u8* out_ptr); From 5c02795af0cbe3ad95c7d3fb2de9891af77e98bb Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 21 Dec 2016 14:01:00 +0100 Subject: [PATCH 3/5] WbfsBlob: Only open each file once The first file used to be opened once by CreateBlobReader and once inside WbfsFileReader. --- Source/Core/DiscIO/Blob.cpp | 2 +- Source/Core/DiscIO/WbfsBlob.cpp | 63 ++++++++++++++++++--------------- Source/Core/DiscIO/WbfsBlob.h | 12 +++++-- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp index e40b530233..7d30cfe212 100644 --- a/Source/Core/DiscIO/Blob.cpp +++ b/Source/Core/DiscIO/Blob.cpp @@ -199,7 +199,7 @@ std::unique_ptr CreateBlobReader(const std::string& filename) case TGC_MAGIC: return TGCFileReader::Create(std::move(file)); case WBFS_MAGIC: - return WbfsFileReader::Create(filename); + return WbfsFileReader::Create(std::move(file), filename); default: return PlainFileReader::Create(std::move(file)); } diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index 58ec6fc4c7..1bc7013aed 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -7,9 +7,11 @@ #include #include #include +#include #include #include "Common/Align.h" +#include "Common/Assert.h" #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" @@ -23,14 +25,15 @@ static const u64 WII_SECTOR_SIZE = 0x8000; static const u64 WII_SECTOR_COUNT = 143432 * 2; static const u64 WII_DISC_HEADER_SIZE = 256; -WbfsFileReader::WbfsFileReader(const std::string& filename) - : m_total_files(0), m_size(0), m_good(true) +WbfsFileReader::WbfsFileReader(File::IOFile file, const std::string& path) + : m_total_files(0), m_size(0), m_good(false) { - if (filename.length() < 4 || !OpenFiles(filename) || !ReadHeader()) - { - m_good = false; + if (!AddFileToList(std::move(file))) return; - } + OpenAdditionalFiles(path); + if (!ReadHeader()) + return; + m_good = true; // Grab disc info (assume slot 0, checked in ReadHeader()) m_wlba_table.resize(m_blocks_per_disc); @@ -50,38 +53,40 @@ u64 WbfsFileReader::GetDataSize() const return WII_SECTOR_COUNT * WII_SECTOR_SIZE; } -bool WbfsFileReader::OpenFiles(const std::string& filename) +void WbfsFileReader::OpenAdditionalFiles(const std::string& path) { - m_total_files = 0; + if (path.length() < 4) + return; + + _assert_(m_total_files > 0); // The code below gives .wbf0 for index 0, but it should be .wbfs while (true) { - auto new_entry = std::make_unique(); - // Replace last character with index (e.g. wbfs = wbf1) - std::string path = filename; - if (m_total_files != 0) - { - path[path.length() - 1] = '0' + m_total_files; - } - - if (!new_entry->file.Open(path, "rb")) - { - return m_total_files != 0; - } - - new_entry->base_address = m_size; - new_entry->size = new_entry->file.GetSize(); - m_size += new_entry->size; - - m_total_files++; - m_files.emplace_back(std::move(new_entry)); + std::string current_path = path; + current_path.back() = '0' + m_total_files; + if (!AddFileToList(File::IOFile(current_path, "rb"))) + return; } } +bool WbfsFileReader::AddFileToList(File::IOFile file) +{ + if (!file.IsOpen()) + return false; + + const u64 file_size = file.GetSize(); + m_files.emplace_back(std::make_unique(std::move(file), m_size, file_size)); + m_size += file_size; + m_total_files++; + + return true; +} + bool WbfsFileReader::ReadHeader() { // Read hd size info + m_files[0]->file.Seek(0, SEEK_SET); m_files[0]->file.ReadBytes(&m_header, sizeof(WbfsHeader)); if (m_header.magic != WBFS_MAGIC) return false; @@ -164,9 +169,9 @@ File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) return m_files[0]->file; } -std::unique_ptr WbfsFileReader::Create(const std::string& filename) +std::unique_ptr WbfsFileReader::Create(File::IOFile file, const std::string& path) { - auto reader = std::unique_ptr(new WbfsFileReader(filename)); + auto reader = std::unique_ptr(new WbfsFileReader(std::move(file), path)); if (!reader->IsGood()) reader.reset(); diff --git a/Source/Core/DiscIO/WbfsBlob.h b/Source/Core/DiscIO/WbfsBlob.h index 5012ccd174..fc55b3ae48 100644 --- a/Source/Core/DiscIO/WbfsBlob.h +++ b/Source/Core/DiscIO/WbfsBlob.h @@ -21,7 +21,7 @@ class WbfsFileReader : public IBlobReader public: ~WbfsFileReader(); - static std::unique_ptr Create(const std::string& filename); + static std::unique_ptr Create(File::IOFile file, const std::string& path); BlobType GetBlobType() const override { return BlobType::WBFS; } // The WBFS format does not save the original file size. @@ -33,15 +33,21 @@ public: bool Read(u64 offset, u64 nbytes, u8* out_ptr) override; private: - WbfsFileReader(const std::string& filename); + WbfsFileReader(File::IOFile file, const std::string& path); - bool OpenFiles(const std::string& filename); + void OpenAdditionalFiles(const std::string& path); + bool AddFileToList(File::IOFile file); bool ReadHeader(); File::IOFile& SeekToCluster(u64 offset, u64* available); bool IsGood() { return m_good; } struct file_entry { + file_entry(File::IOFile file_, u64 base_address_, u64 size_) + : file(std::move(file_)), base_address(base_address_), size(size_) + { + } + File::IOFile file; u64 base_address; u64 size; From 0363be4320af79e732ca797d1fd8a0d2bf0204cf Mon Sep 17 00:00:00 2001 From: JosJuice Date: Wed, 21 Dec 2016 14:05:33 +0100 Subject: [PATCH 4/5] WbfsBlob: Remove m_total_files std::vector already keeps track of this for us. --- Source/Core/DiscIO/WbfsBlob.cpp | 19 ++++++++++--------- Source/Core/DiscIO/WbfsBlob.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index 1bc7013aed..397c0d8ee1 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -26,7 +26,7 @@ static const u64 WII_SECTOR_COUNT = 143432 * 2; static const u64 WII_DISC_HEADER_SIZE = 256; WbfsFileReader::WbfsFileReader(File::IOFile file, const std::string& path) - : m_total_files(0), m_size(0), m_good(false) + : m_size(0), m_good(false) { if (!AddFileToList(std::move(file))) return; @@ -58,13 +58,15 @@ void WbfsFileReader::OpenAdditionalFiles(const std::string& path) if (path.length() < 4) return; - _assert_(m_total_files > 0); // The code below gives .wbf0 for index 0, but it should be .wbfs + _assert_(m_files.size() > 0); // The code below gives .wbf0 for index 0, but it should be .wbfs while (true) { // Replace last character with index (e.g. wbfs = wbf1) + if (m_files.size() >= 10) + return; std::string current_path = path; - current_path.back() = '0' + m_total_files; + current_path.back() = static_cast('0' + m_files.size()); if (!AddFileToList(File::IOFile(current_path, "rb"))) return; } @@ -78,7 +80,6 @@ bool WbfsFileReader::AddFileToList(File::IOFile file) const u64 file_size = file.GetSize(); m_files.emplace_back(std::make_unique(std::move(file), m_size, file_size)); m_size += file_size; - m_total_files++; return true; } @@ -145,19 +146,19 @@ File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) 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++) + for (const std::unique_ptr& file_entry : m_files) { - if (final_address < (m_files[i]->base_address + m_files[i]->size)) + if (final_address < (file_entry->base_address + file_entry->size)) { - m_files[i]->file.Seek(final_address - m_files[i]->base_address, SEEK_SET); + file_entry->file.Seek(final_address - file_entry->base_address, SEEK_SET); if (available) { - u64 till_end_of_file = m_files[i]->size - (final_address - m_files[i]->base_address); + u64 till_end_of_file = file_entry->size - (final_address - file_entry->base_address); u64 till_end_of_sector = m_wbfs_sector_size - cluster_offset; *available = std::min(till_end_of_file, till_end_of_sector); } - return m_files[i]->file; + return file_entry->file; } } } diff --git a/Source/Core/DiscIO/WbfsBlob.h b/Source/Core/DiscIO/WbfsBlob.h index fc55b3ae48..b516e04c36 100644 --- a/Source/Core/DiscIO/WbfsBlob.h +++ b/Source/Core/DiscIO/WbfsBlob.h @@ -55,7 +55,6 @@ private: std::vector> m_files; - u32 m_total_files; u64 m_size; u64 m_hd_sector_size; From b1873264d7c78ea02de16691d26881eb2c4a47e1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 31 Dec 2016 22:51:16 +0100 Subject: [PATCH 5/5] WbfsBlob: Don't wrap file_entry in std::unique_ptr There doesn't seem to be any reason for doing it. --- Source/Core/DiscIO/WbfsBlob.cpp | 26 +++++++++++++------------- Source/Core/DiscIO/WbfsBlob.h | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Source/Core/DiscIO/WbfsBlob.cpp b/Source/Core/DiscIO/WbfsBlob.cpp index 397c0d8ee1..8c29d93202 100644 --- a/Source/Core/DiscIO/WbfsBlob.cpp +++ b/Source/Core/DiscIO/WbfsBlob.cpp @@ -37,9 +37,9 @@ WbfsFileReader::WbfsFileReader(File::IOFile file, const std::string& path) // Grab disc info (assume slot 0, checked in ReadHeader()) m_wlba_table.resize(m_blocks_per_disc); - 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.data(), m_blocks_per_disc * sizeof(u16)); + 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.data(), m_blocks_per_disc * sizeof(u16)); for (size_t i = 0; i < m_blocks_per_disc; i++) m_wlba_table[i] = Common::swap16(m_wlba_table[i]); } @@ -78,7 +78,7 @@ bool WbfsFileReader::AddFileToList(File::IOFile file) return false; const u64 file_size = file.GetSize(); - m_files.emplace_back(std::make_unique(std::move(file), m_size, file_size)); + m_files.emplace_back(std::move(file), m_size, file_size); m_size += file_size; return true; @@ -87,8 +87,8 @@ bool WbfsFileReader::AddFileToList(File::IOFile file) bool WbfsFileReader::ReadHeader() { // Read hd size info - m_files[0]->file.Seek(0, SEEK_SET); - m_files[0]->file.ReadBytes(&m_header, sizeof(WbfsHeader)); + m_files[0].file.Seek(0, SEEK_SET); + m_files[0].file.ReadBytes(&m_header, sizeof(WbfsHeader)); if (m_header.magic != WBFS_MAGIC) return false; @@ -146,19 +146,19 @@ File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) u64 cluster_offset = offset & (m_wbfs_sector_size - 1); u64 final_address = cluster_address + cluster_offset; - for (const std::unique_ptr& file_entry : m_files) + for (file_entry& file_entry : m_files) { - if (final_address < (file_entry->base_address + file_entry->size)) + if (final_address < (file_entry.base_address + file_entry.size)) { - file_entry->file.Seek(final_address - file_entry->base_address, SEEK_SET); + file_entry.file.Seek(final_address - file_entry.base_address, SEEK_SET); if (available) { - u64 till_end_of_file = file_entry->size - (final_address - file_entry->base_address); + u64 till_end_of_file = file_entry.size - (final_address - file_entry.base_address); u64 till_end_of_sector = m_wbfs_sector_size - cluster_offset; *available = std::min(till_end_of_file, till_end_of_sector); } - return file_entry->file; + return file_entry.file; } } } @@ -166,8 +166,8 @@ File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) PanicAlert("Read beyond end of disc"); if (available) *available = 0; - m_files[0]->file.Seek(0, SEEK_SET); - return m_files[0]->file; + m_files[0].file.Seek(0, SEEK_SET); + return m_files[0].file; } std::unique_ptr WbfsFileReader::Create(File::IOFile file, const std::string& path) diff --git a/Source/Core/DiscIO/WbfsBlob.h b/Source/Core/DiscIO/WbfsBlob.h index b516e04c36..f2c0d4bfa7 100644 --- a/Source/Core/DiscIO/WbfsBlob.h +++ b/Source/Core/DiscIO/WbfsBlob.h @@ -53,7 +53,7 @@ private: u64 size; }; - std::vector> m_files; + std::vector m_files; u64 m_size;