Created
May 17, 2023 17:41
-
-
Save pfirsich/5c7b67272ea1db924f6d141e50c377ea to your computer and use it in GitHub Desktop.
An example of a C++ wrapper for `PHYSFS_Io`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <fmt/format.h> | |
#include <physfs.h> | |
template <typename Derived> | |
struct PhysfsIo : PHYSFS_Io { | |
protected: | |
PhysfsIo() | |
: PHYSFS_Io { | |
.version = Derived::version, | |
.opaque = this, | |
.read = staticRead, // may be NULL | |
.write = staticWrite, // may be NULL | |
.seek = staticSeek, | |
.tell = staticTell, | |
.length = staticLength, | |
.duplicate = staticDuplicate, | |
.flush = staticFlush, // may be NULL | |
.destroy = staticDestroy, | |
} | |
{ | |
} | |
private: | |
static PHYSFS_sint64 staticRead(struct PHYSFS_Io* io, void* buf, PHYSFS_uint64 len) | |
{ | |
return derived(io)->read(buf, len); | |
} | |
static PHYSFS_sint64 staticWrite(struct PHYSFS_Io* io, const void* buf, PHYSFS_uint64 len) | |
{ | |
return derived(io)->write(buf, len); | |
} | |
static int staticSeek(struct PHYSFS_Io* io, PHYSFS_uint64 offset) | |
{ | |
return derived(io)->seek(offset); | |
} | |
static PHYSFS_sint64 staticTell(struct PHYSFS_Io* io) { return derived(io)->tell(); } | |
static PHYSFS_sint64 staticLength(struct PHYSFS_Io* io) { return derived(io)->length(); } | |
static struct PHYSFS_Io* staticDuplicate(struct PHYSFS_Io* io) | |
{ | |
// Just use copy constructor | |
return new Derived(*derived(io)); | |
} | |
static int staticFlush(struct PHYSFS_Io* io) { return derived(io)->flush(); } | |
static void staticDestroy(struct PHYSFS_Io* io) | |
{ | |
// Just use destructor | |
delete derived(io); | |
} | |
static Derived* derived(PHYSFS_Io* io) | |
{ | |
return static_cast<Derived*>(reinterpret_cast<PhysfsIo*>(io->opaque)); | |
} | |
}; | |
struct PhysfsCStdio : public PhysfsIo<PhysfsCStdio> { | |
static constexpr uint32_t version = 0; | |
std::string filename; | |
FILE* file; | |
// The constructor is private in favor of this function to prevent stack allocation | |
// because Physfs will take ownership of this object. | |
static PhysfsCStdio* create(std::string f) { return new PhysfsCStdio(f); } | |
~PhysfsCStdio() { std::fclose(file); } | |
PhysfsCStdio(const PhysfsCStdio& other) | |
: PhysfsCStdio(other.filename) | |
{ | |
} | |
int64_t read(void* buf, uint64_t len); | |
int64_t write(const void* buf, uint64_t len); | |
int64_t seek(uint64_t offset); | |
int64_t tell(); | |
int64_t length(); | |
int64_t flush(); | |
private: | |
PhysfsCStdio(std::string f) | |
: filename(std::move(f)) | |
, file(std::fopen(filename.c_str(), "rb")) | |
{ | |
} | |
}; | |
void enumerateDirectory(const std::string& dir, size_t level = 0) | |
{ | |
const auto ret = PHYSFS_enumerateFiles(dir.c_str()); | |
std::string indent(level, ' '); | |
for (auto i = ret; *i != nullptr; ++i) { | |
auto path = dir + "/" + *i; | |
fmt::print("{}{}\n", indent, path); | |
printDirectory(path, level + 1); | |
} | |
PHYSFS_freeList(ret); | |
} | |
int main(int argc, char** argv) | |
{ | |
if (argc < 3) { | |
fmt::print(stderr, "Usage: physfs_enumerate <exe>\n"); | |
return 1; | |
} | |
const auto exe = argv[1]; | |
PHYSFS_init(argv[0]); | |
auto io = PhysfsCStdio::create(exe); | |
if (!PHYSFS_mountIo(io, io->filename.c_str(), nullptr, 1)) { | |
fmt::print(stderr, "Error mounting exe file\n"); | |
delete io; | |
return 1; | |
} | |
enumerateDirectory(""); | |
PHYSFS_deinit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment