Skip to content

Instantly share code, notes, and snippets.

@pfirsich
Created May 17, 2023 17:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfirsich/5c7b67272ea1db924f6d141e50c377ea to your computer and use it in GitHub Desktop.
Save pfirsich/5c7b67272ea1db924f6d141e50c377ea to your computer and use it in GitHub Desktop.
An example of a C++ wrapper for `PHYSFS_Io`
#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