FileSystem: Allow ::openReadRaw() to break out of game directory

If PhysFS fails to open a path, fall back to simple FILE* handles.
Not sure yet if this is a good idea, but from observation
RMXP allows load_data() to operate on paths outside the game
directory as well, so we have to support this.
This commit is contained in:
Ancurio 2021-09-23 18:32:10 +02:00 committed by Jonas Kulla
parent 7938a07539
commit d45a400227
5 changed files with 33 additions and 40 deletions

View File

@ -33,7 +33,6 @@ fileIntFreeInstance(void *inst)
{ {
SDL_RWops *ops = static_cast<SDL_RWops*>(inst); SDL_RWops *ops = static_cast<SDL_RWops*>(inst);
SDL_RWclose(ops);
SDL_FreeRW(ops); SDL_FreeRW(ops);
} }
@ -42,16 +41,14 @@ DEF_TYPE_CUSTOMFREE(FileInt, fileIntFreeInstance);
static VALUE static VALUE
fileIntForPath(const char *path, bool rubyExc) fileIntForPath(const char *path, bool rubyExc)
{ {
SDL_RWops *ops = SDL_AllocRW(); SDL_RWops *ops;
try try
{ {
shState->fileSystem().openReadRaw(*ops, path); ops = shState->fileSystem().openReadRaw(path);
} }
catch (const Exception &e) catch (const Exception &e)
{ {
SDL_FreeRW(ops);
if (rubyExc) if (rubyExc)
raiseRbExc(e); raiseRbExc(e);
else else

View File

@ -273,23 +273,23 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
/* We use a secondary util state to unmarshal the scripts */ /* We use a secondary util state to unmarshal the scripts */
mrb_state *scriptMrb = mrb_open(); mrb_state *scriptMrb = mrb_open();
SDL_RWops ops;
shState->fileSystem().openReadRaw(ops, scriptPack.c_str()); SDL_RWops *ops = shState->fileSystem().openReadRaw(scriptPack.c_str());
mrb_value scriptArray = mrb_nil_value(); mrb_value scriptArray = mrb_nil_value();
std::string readError; std::string readError;
try try
{ {
scriptArray = marshalLoadInt(scriptMrb, &ops); scriptArray = marshalLoadInt(scriptMrb, ops);
} }
catch (const Exception &e) catch (const Exception &e)
{ {
readError = std::string(": ") + e.msg; readError = std::string(": ") + e.msg;
} }
SDL_RWclose(&ops); SDL_RWclose(ops);
SDL_FreeRW(ops);
if (!mrb_array_p(scriptArray)) if (!mrb_array_p(scriptArray))
{ {

View File

@ -222,15 +222,6 @@ static int SDL_RWopsClose(SDL_RWops *ops)
return (result != 0) ? 0 : -1; return (result != 0) ? 0 : -1;
} }
static int SDL_RWopsCloseFree(SDL_RWops *ops)
{
int result = SDL_RWopsClose(ops);
SDL_FreeRW(ops);
return result;
}
/* Copies the first srcN characters from src into dst, /* Copies the first srcN characters from src into dst,
* or the full string if srcN == -1. Never writes more * or the full string if srcN == -1. Never writes more
* than dstMax, and guarantees dst to be null terminated. * than dstMax, and guarantees dst to be null terminated.
@ -272,18 +263,13 @@ findExt(const char *filename)
static void static void
initReadOps(PHYSFS_File *handle, initReadOps(PHYSFS_File *handle,
SDL_RWops &ops, SDL_RWops &ops)
bool freeOnClose)
{ {
ops.size = SDL_RWopsSize; ops.size = SDL_RWopsSize;
ops.seek = SDL_RWopsSeek; ops.seek = SDL_RWopsSeek;
ops.read = SDL_RWopsRead; ops.read = SDL_RWopsRead;
ops.write = SDL_RWopsWrite; ops.write = SDL_RWopsWrite;
ops.close = SDL_RWopsClose;
if (freeOnClose)
ops.close = SDL_RWopsCloseFree;
else
ops.close = SDL_RWopsClose;
ops.type = SDL_RWOPS_PHYSFS; ops.type = SDL_RWOPS_PHYSFS;
ops.hidden.unknown.data1 = handle; ops.hidden.unknown.data1 = handle;
@ -504,7 +490,7 @@ fontSetEnumCB (void *data, const char *dir, const char *fname)
return PHYSFS_ENUM_ERROR; return PHYSFS_ENUM_ERROR;
SDL_RWops ops; SDL_RWops ops;
initReadOps(handle, ops, false); initReadOps(handle, ops);
d->sfs->initFontSetCB(ops, filename); d->sfs->initFontSetCB(ops, filename);
@ -620,7 +606,7 @@ openReadEnumCB(void *d, const char *dirpath, const char *filename)
return PHYSFS_ENUM_ERROR; return PHYSFS_ENUM_ERROR;
} }
initReadOps(phys, data.ops, false); initReadOps(phys, data.ops);
const char *ext = findExt(filename); const char *ext = findExt(filename);
@ -684,14 +670,27 @@ void FileSystem::openRead(OpenHandler &handler, const char *filename)
throw Exception(Exception::NoFileError, "%s", filename); throw Exception(Exception::NoFileError, "%s", filename);
} }
void FileSystem::openReadRaw(SDL_RWops &ops, SDL_RWops *FileSystem::openReadRaw(const char *filename)
const char *filename,
bool freeOnClose)
{ {
PHYSFS_File *handle = PHYSFS_openRead(filename); SDL_RWops *ops;
assert(handle);
initReadOps(handle, ops, freeOnClose); PHYSFS_File *handle = PHYSFS_openRead(filename);
if (!handle) {
Debug() << "Couldn't open " << filename << " via PhysFS; trying normal FILE*";
ops = SDL_RWFromFile(filename, "rb");
if (!ops) {
Debug() << "FILE* path failed too..";
throw Exception(Exception::NoFileError, "%s", filename);
}
}
else
{
ops = SDL_AllocRW();
initReadOps(handle, *ops);
}
return ops;
} }
bool FileSystem::exists(const char *filename) bool FileSystem::exists(const char *filename)

View File

@ -60,9 +60,7 @@ public:
const char *filename); const char *filename);
/* Circumvents extension supplementing */ /* Circumvents extension supplementing */
void openReadRaw(SDL_RWops &ops, SDL_RWops *openReadRaw(const char *filename);
const char *filename,
bool freeOnClose = false);
/* Does not perform extension supplementing */ /* Does not perform extension supplementing */
bool exists(const char *filename); bool exists(const char *filename);

View File

@ -167,14 +167,13 @@ _TTF_Font *SharedFontState::getFont(std::string family,
const char *path = !req.regular.empty() const char *path = !req.regular.empty()
? req.regular.c_str() : req.other.c_str(); ? req.regular.c_str() : req.other.c_str();
ops = SDL_AllocRW(); ops = shState->fileSystem().openReadRaw(path);
shState->fileSystem().openReadRaw(*ops, path, true);
} }
// FIXME 0.9 is guesswork at this point // FIXME 0.9 is guesswork at this point
// float gamma = (96.0/45.0)*(5.0/14.0)*(size-5); // float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
// font = TTF_OpenFontRW(ops, 1, gamma /** .90*/); // font = TTF_OpenFontRW(ops, 0, gamma /** .90*/);
font = TTF_OpenFontRW(ops, 1, size* 0.90f); font = TTF_OpenFontRW(ops, 0, size* 0.90f);
if (!font) if (!font)
throw Exception(Exception::SDLError, "%s", SDL_GetError()); throw Exception(Exception::SDLError, "%s", SDL_GetError());