Add more filesystem functionality;

This commit is contained in:
bjorn 2017-03-11 01:37:00 -08:00
parent 8525601538
commit 4df4069915
9 changed files with 222 additions and 107 deletions

View File

@ -5,53 +5,84 @@
#include <stdlib.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#elif _WIN32
#endif
#if _WIN32
#include <windows.h>
#include <initguid.h>
#include <KnownFolders.h>
#include <ShlObj.h>
#include <wchar.h>
#else
#include <unistd.h>
#include <pwd.h>
#endif
static FilesystemState state;
void lovrFilesystemInit(const char* arg0) {
void lovrFilesystemInit(const char* arg0, const char* arg1) {
if (!PHYSFS_init(arg0)) {
error("Could not initialize filesystem: %s", PHYSFS_getLastError());
}
state.gameSource = NULL;
state.source = malloc(LOVR_PATH_MAX * sizeof(char));
state.identity = NULL;
state.isFused = 1;
// Try to mount either an archive fused to the executable or an archive from the command line
lovrFilesystemGetExecutablePath(state.source, LOVR_PATH_MAX);
if (lovrFilesystemMount(state.source, NULL, 1)) {
state.isFused = 0;
strncpy(state.source, arg1, LOVR_PATH_MAX);
if (!state.source || lovrFilesystemMount(state.source, NULL, 1)) {
free(state.source);
state.source = NULL;
}
}
atexit(lovrFilesystemDestroy);
}
void lovrFilesystemDestroy() {
free(state.source);
free(state.savePathFull);
free(state.savePathRelative);
PHYSFS_deinit();
}
int lovrFilesystemAppend(const char* path, const char* content, int size) {
if (!PHYSFS_isInit() || !state.identity) {
error("Can not write files until lovr.filesystem.setIdentity is called");
}
// Open file
PHYSFS_file* handle = PHYSFS_openAppend(path);
if (!handle) {
return 0;
}
// Perform write
int bytesWritten = PHYSFS_write(handle, content, 1, size);
PHYSFS_close(handle);
return bytesWritten;
int lovrFilesystemCreateDirectory(const char* path) {
return !PHYSFS_mkdir(path);
}
int lovrFilesystemExists(const char* path) {
return PHYSFS_exists(path);
}
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size) {
#ifdef __APPLE__
const char* home;
if ((home = getenv("HOME")) == NULL) {
home = getpwuid(getuid())->pw_dir;
}
snprintf(dest, size, "%s/Library/Application Support", home);
return 0;
#elif _WIN32
PWSTR appData = NULL;
SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &appData);
wcstombs(dest, appData, size);
CoTaskMemFree(appData);
return 0;
#else
#error "This platform is missing an implementation for lovrFilesystemGetAppdataDirectory"
#endif
return 1;
}
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata) {
PHYSFS_enumerateFilesCallback(path, callback, userdata);
}
int lovrFilesystemGetExecutablePath(char* dest, unsigned int size) {
#ifdef __APPLE__
if (_NSGetExecutablePath(dest, &size) == 0) {
@ -70,23 +101,34 @@ const char* lovrFilesystemGetIdentity() {
return state.identity;
}
const char* lovrFilesystemGetRealDirectory(const char* path) {
if (!PHYSFS_isInit()) {
return NULL;
}
long lovrFilesystemGetLastModified(const char* path) {
return PHYSFS_getLastModTime(path);
}
const char* lovrFilesystemGetRealDirectory(const char* path) {
return PHYSFS_getRealDir(path);
}
const char* lovrFilesystemGetSaveDirectory() {
return state.savePathFull;
}
int lovrFilesystemGetSize(const char* path) {
PHYSFS_file* handle = PHYSFS_openRead(path);
if (!handle) {
return 1;
}
int length = PHYSFS_fileLength(handle);
PHYSFS_close(handle);
return length;
}
const char* lovrFilesystemGetSource() {
return state.gameSource;
return state.source;
}
const char* lovrFilesystemGetUserDirectory() {
if (!PHYSFS_isInit()) {
return NULL;
}
return PHYSFS_getUserDir();
}
@ -98,10 +140,15 @@ int lovrFilesystemIsFile(const char* path) {
return lovrFilesystemExists(path) && !lovrFilesystemIsDirectory(path);
}
void* lovrFilesystemRead(const char* path, int* bytesRead) {
if (!PHYSFS_isInit()) {
return NULL;
}
int lovrFilesystemIsFused() {
return state.isFused;
}
int lovrFilesystemMount(const char* path, const char* mountpoint, int append) {
return !PHYSFS_mount(path, mountpoint, append);
}
void* lovrFilesystemRead(const char* path, size_t* bytesRead) {
// Open file
PHYSFS_file* handle = PHYSFS_openRead(path);
@ -126,7 +173,7 @@ void* lovrFilesystemRead(const char* path, int* bytesRead) {
PHYSFS_close(handle);
// Make sure we got everything
if (*bytesRead != size) {
if (*bytesRead != (size_t) size) {
free(data);
return NULL;
}
@ -134,6 +181,10 @@ void* lovrFilesystemRead(const char* path, int* bytesRead) {
return data;
}
int lovrFilesystemRemove(const char* path) {
return !PHYSFS_delete(path);
}
int lovrFilesystemSetIdentity(const char* identity) {
state.identity = identity;
@ -143,58 +194,32 @@ int lovrFilesystemSetIdentity(const char* identity) {
} else {
state.savePathRelative = malloc(LOVR_PATH_MAX);
state.savePathFull = malloc(LOVR_PATH_MAX);
if (!state.savePathRelative || !state.savePathFull) {
return 1;
}
}
// Set new write directory
#ifdef __APPLE__
const char* userDir = PHYSFS_getUserDir();
PHYSFS_setWriteDir(userDir);
snprintf(state.savePathRelative, LOVR_PATH_MAX, "Library/Application Support/LOVR/%s", identity);
PHYSFS_mkdir(state.savePathRelative);
snprintf(state.savePathFull, LOVR_PATH_MAX, "%s%s", userDir, state.savePathRelative);
if (PHYSFS_setWriteDir(state.savePathFull)) {
PHYSFS_mount(state.savePathFull, NULL, 0);
return 0;
}
#elif _WIN32
PWSTR appData = NULL;
SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &appData);
lovrFilesystemGetAppdataDirectory(state.savePathFull, LOVR_PATH_MAX);
PHYSFS_setWriteDir(state.savePathFull);
snprintf(state.savePathRelative, LOVR_PATH_MAX, "LOVR/%s", identity);
CoTaskMemFree(appData);
#else
#error "This platform is missing an implementation of lovrFilesystemSetIdentity"
#endif
snprintf(state.savePathFull, LOVR_PATH_MAX, "%s/%s", state.savePathFull, state.savePathRelative);
PHYSFS_mkdir(state.savePathRelative);
PHYSFS_setWriteDir(state.savePathRelative);
PHYSFS_mount(state.savePathFull, NULL, 0);
return 1;
return 0;
}
int lovrFilesystemSetSource(const char* source) {
if (state.gameSource) {
return 1;
}
if (PHYSFS_mount(source, NULL, 0)) {
state.gameSource = source;
return 0;
}
return 1;
int lovrFilesystemUnmount(const char* path) {
return !PHYSFS_removeFromSearchPath(path);
}
int lovrFilesystemWrite(const char* path, const char* content, int size) {
if (!PHYSFS_isInit() || !state.identity) {
error("Can not write files until lovr.filesystem.setIdentity is called");
}
// Open file
PHYSFS_file* handle = PHYSFS_openWrite(path);
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append) {
PHYSFS_file* handle = append ? PHYSFS_openAppend(path) : PHYSFS_openWrite(path);
if (!handle) {
return 0;
}
// Perform write
int bytesWritten = PHYSFS_write(handle, content, 1, size);
PHYSFS_close(handle);
return bytesWritten;

View File

@ -1,26 +1,39 @@
#include <stdio.h>
#pragma once
#define LOVR_PATH_MAX 1024
typedef void getDirectoryItemsCallback(void* userdata, const char* dir, const char* file);
typedef struct {
const char* gameSource;
char* source;
const char* identity;
char* savePathRelative;
char* savePathFull;
int isFused;
} FilesystemState;
void lovrFilesystemInit(const char* arg0);
void lovrFilesystemInit(const char* arg0, const char* arg1);
void lovrFilesystemDestroy();
int lovrFilesystemAppend(const char* path, const char* content, int size);
int lovrFilesystemExists(const char* path);
int lovrFilesystemGetAppdataDirectory(char* dest, unsigned int size);
void lovrFilesystemGetDirectoryItems(const char* path, getDirectoryItemsCallback callback, void* userdata);
int lovrFilesystemGetExecutablePath(char* dest, unsigned int size);
const char* lovrFilesystemGetIdentity();
long lovrFilesystemGetLastModified(const char* path);
const char* lovrFilesystemGetRealDirectory(const char* path);
const char* lovrFilesystemGetSaveDirectory();
int lovrFilesystemGetSize(const char* path);
const char* lovrFilesystemGetSource();
const char* lovrFilesystemGetUserDirectory();
int lovrFilesystemIsDirectory(const char* path);
int lovrFilesystemIsFile(const char* path);
void* lovrFilesystemRead(const char* path, int* bytesRead);
int lovrFilesystemIsFused();
int lovrFilesystemMount(const char* path, const char* mountpoint, int append);
void* lovrFilesystemRead(const char* path, size_t* bytesRead);
int lovrFilesystemRemove(const char* path);
int lovrFilesystemSetIdentity(const char* identity);
int lovrFilesystemSetSource(const char* source);
int lovrFilesystemWrite(const char* path, const char* content, int size);
int lovrFilesystemUnmount(const char* path);
int lovrFilesystemWrite(const char* path, const char* content, size_t size, int append);

View File

@ -2,7 +2,7 @@
#include "vendor/stb/stb_image.h"
#include <stdlib.h>
Skybox* lovrSkyboxCreate(void** data, int* size) {
Skybox* lovrSkyboxCreate(void** data, size_t* size) {
Skybox* skybox = lovrAlloc(sizeof(Skybox), lovrSkyboxDestroy);
if (!skybox) return NULL;

View File

@ -8,5 +8,5 @@ typedef struct {
GLuint texture;
} Skybox;
Skybox* lovrSkyboxCreate(void** data, int* size);
Skybox* lovrSkyboxCreate(void** data, size_t* size);
void lovrSkyboxDestroy(const Ref* ref);

View File

@ -88,10 +88,6 @@ void lovrInit(lua_State* L, int argc, char** argv) {
"} "
"lovr.filesystem = require('lovr.filesystem') "
"lovr.filesystem.init(arg[-2]) "
"if not lovr.filesystem.setSource(lovr.filesystem.getExecutablePath()) and arg[1] then "
" lovr.filesystem.setSource(arg[1]) "
"end "
"local success, err = pcall(require, 'conf') "
"if lovr.conf then "

View File

@ -96,7 +96,7 @@ int l_lovrAudioNewSource(lua_State* L) {
return luaL_error(L, "Only .ogg files are supported");
}
int size;
size_t size;
void* data = lovrFilesystemRead(filename, &size);
if (!data) {
return luaL_error(L, "Could not load source from file '%s'", filename);

View File

@ -3,6 +3,13 @@
#include <stdlib.h>
#include <string.h>
static void pushDirectoryItem(void* userdata, const char* path, const char* filename) {
lua_State* L = userdata;
int n = lua_objlen(L, -1);
lua_pushstring(L, filename);
lua_rawseti(L, -2, n + 1);
}
// Loader to help Lua's require understand PhysFS.
static int filesystemLoader(lua_State* L) {
const char* module = luaL_checkstring(L, -1);
@ -30,7 +37,7 @@ static int filesystemLoader(lua_State* L) {
strncat(filename, requirePath[i] + index + 1, strlen(requirePath[i]) - index);
if (lovrFilesystemIsFile(filename)) {
int size;
size_t size;
void* data = lovrFilesystemRead(filename, &size);
if (data) {
@ -48,20 +55,24 @@ static int filesystemLoader(lua_State* L) {
}
const luaL_Reg lovrFilesystem[] = {
{ "init", l_lovrFilesystemInitialize },
{ "append", l_lovrFilesystemAppend },
{ "exists", l_lovrFilesystemExists },
{ "getAppdataDirectory", l_lovrFilesystemGetAppdataDirectory },
{ "getDirectoryItems", l_lovrFilesystemGetDirectoryItems },
{ "getExecutablePath", l_lovrFilesystemGetExecutablePath },
{ "getIdentity", l_lovrFilesystemGetIdentity },
{ "getRealDirectory", l_lovrFilesystemGetRealDirectory },
{ "getSaveDirectory", l_lovrFilesystemGetSaveDirectory },
{ "getSource", l_lovrFilesystemGetSource },
{ "getUserDirectory", l_lovrFilesystemGetUserDirectory },
{ "isDirectory", l_lovrFilesystemIsDirectory },
{ "isFile", l_lovrFilesystemIsFile },
{ "isFused", l_lovrFilesystemIsFused },
{ "load", l_lovrFilesystemLoad },
{ "mount", l_lovrFilesystemMount },
{ "read", l_lovrFilesystemRead },
{ "remove", l_lovrFilesystemRemove },
{ "setIdentity", l_lovrFilesystemSetIdentity },
{ "setSource", l_lovrFilesystemSetSource },
{ "write", l_lovrFilesystemWrite },
{ NULL, NULL }
};
@ -70,6 +81,14 @@ int l_lovrFilesystemInit(lua_State* L) {
lua_newtable(L);
luaL_register(L, NULL, lovrFilesystem);
lua_getglobal(L, "arg");
lua_rawgeti(L, -1, -2);
lua_rawgeti(L, -2, 1);
const char* arg0 = lua_tostring(L, -2);
const char* arg1 = lua_tostring(L, -1);
lovrFilesystemInit(arg0, arg1);
lua_pop(L, 3);
// Add custom package loader
lua_getglobal(L, "table");
lua_getfield(L, -1, "insert");
@ -87,17 +106,11 @@ int l_lovrFilesystemInit(lua_State* L) {
return 1;
}
int l_lovrFilesystemInitialize(lua_State* L) {
const char* arg0 = luaL_checkstring(L, 1);
lovrFilesystemInit(arg0);
return 0;
}
int l_lovrFilesystemAppend(lua_State* L) {
size_t size;
const char* path = luaL_checkstring(L, 1);
const char* content = luaL_checklstring(L, 2, &size);
lua_pushnumber(L, lovrFilesystemAppend(path, content, size));
lua_pushnumber(L, lovrFilesystemWrite(path, content, size, 1));
return 1;
}
@ -107,6 +120,25 @@ int l_lovrFilesystemExists(lua_State* L) {
return 1;
}
int l_lovrFilesystemGetAppdataDirectory(lua_State* L) {
char buffer[1024];
if (lovrFilesystemGetExecutablePath(buffer, sizeof(buffer))) {
lua_pushnil(L);
} else {
lua_pushstring(L, buffer);
}
return 1;
}
int l_lovrFilesystemGetDirectoryItems(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
lua_newtable(L);
lovrFilesystemGetDirectoryItems(path, pushDirectoryItem, L);
return 1;
}
int l_lovrFilesystemGetExecutablePath(lua_State* L) {
char buffer[1024];
@ -124,12 +156,36 @@ int l_lovrFilesystemGetIdentity(lua_State* L) {
return 1;
}
int l_lovrFilesystemGetLastModified(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
int lastModified = lovrFilesystemGetLastModified(path);
if (lastModified < 0) {
lua_pushnil(L);
} else {
lua_pushinteger(L, lastModified);
}
return 1;
}
int l_lovrFilesystemGetRealDirectory(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
lua_pushstring(L, lovrFilesystemGetRealDirectory(path));
return 1;
}
int l_lovrFilesystemGetSaveDirectory(lua_State* L) {
lua_pushstring(L, lovrFilesystemGetSaveDirectory());
return 1;
}
int l_lovrFilesystemGetSize(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
lua_pushinteger(L, lovrFilesystemGetSize(path));
return 1;
}
int l_lovrFilesystemGetSource(lua_State* L) {
lua_pushstring(L, lovrFilesystemGetSource());
return 1;
@ -152,9 +208,14 @@ int l_lovrFilesystemIsFile(lua_State* L) {
return 1;
}
int l_lovrFilesystemIsFused(lua_State* L) {
lua_pushboolean(L, lovrFilesystemIsFused());
return 1;
}
int l_lovrFilesystemLoad(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
int size;
size_t size;
char* content = lovrFilesystemRead(path, &size);
int status = luaL_loadbuffer(L, content, size, path);
@ -165,9 +226,17 @@ int l_lovrFilesystemLoad(lua_State* L) {
}
}
int l_lovrFilesystemMount(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
const char* mountpoint = luaL_optstring(L, 2, NULL);
int append = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
lua_pushboolean(L, !lovrFilesystemMount(path, mountpoint, append));
return 1;
}
int l_lovrFilesystemRead(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
int size;
size_t size;
char* content = lovrFilesystemRead(path, &size);
if (!content) {
return luaL_error(L, "Could not read file '%s'", path);
@ -178,6 +247,12 @@ int l_lovrFilesystemRead(lua_State* L) {
return 1;
}
int l_lovrFilesystemRemove(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
lua_pushboolean(L, !lovrFilesystemRemove(path));
return 1;
}
int l_lovrFilesystemSetIdentity(lua_State* L) {
const char* identity = luaL_checkstring(L, 1);
@ -188,9 +263,9 @@ int l_lovrFilesystemSetIdentity(lua_State* L) {
return 0;
}
int l_lovrFilesystemSetSource(lua_State* L) {
const char* source = luaL_checkstring(L, 1);
lua_pushboolean(L, !lovrFilesystemSetSource(source));
int l_lovrFilesystemUnmount(lua_State* L) {
const char* path = luaL_checkstring(L, 1);
lua_pushboolean(L, !lovrFilesystemUnmount(path));
return 1;
}
@ -198,6 +273,6 @@ int l_lovrFilesystemWrite(lua_State* L) {
size_t size;
const char* path = luaL_checkstring(L, 1);
const char* content = luaL_checklstring(L, 2, &size);
lua_pushnumber(L, lovrFilesystemWrite(path, content, size));
lua_pushnumber(L, lovrFilesystemWrite(path, content, size, 0));
return 1;
}

View File

@ -2,18 +2,24 @@
extern const luaL_Reg lovrFilesystem[];
int l_lovrFilesystemInit(lua_State* L);
int l_lovrFilesystemInitialize(lua_State* L);
int l_lovrFilesystemAppend(lua_State* L);
int l_lovrFilesystemExists(lua_State* L);
int l_lovrFilesystemGetAppdataDirectory(lua_State* L);
int l_lovrFilesystemGetDirectoryItems(lua_State* L);
int l_lovrFilesystemGetExecutablePath(lua_State* L);
int l_lovrFilesystemGetIdentity(lua_State* L);
int l_lovrFilesystemGetLastModified(lua_State* L);
int l_lovrFilesystemGetRealDirectory(lua_State* L);
int l_lovrFilesystemGetSaveDirectory(lua_State* L);
int l_lovrFilesystemGetSource(lua_State* L);
int l_lovrFilesystemGetUserDirectory(lua_State* L);
int l_lovrFilesystemIsDirectory(lua_State* L);
int l_lovrFilesystemIsFile(lua_State* L);
int l_lovrFilesystemIsFused(lua_State* L);
int l_lovrFilesystemLoad(lua_State* L);
int l_lovrFilesystemMount(lua_State* L);
int l_lovrFilesystemRead(lua_State* L);
int l_lovrFilesystemRemove(lua_State* L);
int l_lovrFilesystemSetIdentity(lua_State* L);
int l_lovrFilesystemSetSource(lua_State* L);
int l_lovrFilesystemUnmount(lua_State* L);
int l_lovrFilesystemWrite(lua_State* L);

View File

@ -45,7 +45,7 @@ static void luax_readvertices(lua_State* L, int index, vec_float_t* points) {
static Texture* luax_readtexture(lua_State* L, int index) {
const char* path = luaL_checkstring(L, index);
int size;
size_t size;
void* data = lovrFilesystemRead(path, &size);
if (!data) {
luaL_error(L, "Could not load texture file '%s'", path);
@ -636,7 +636,7 @@ int l_lovrGraphicsNewBuffer(lua_State* L) {
int l_lovrGraphicsNewFont(lua_State* L) {
void* data = NULL;
int size = 0;
size_t size = 0;
float fontSize;
if (lua_type(L, 1) == LUA_TNUMBER || lua_isnoneornil(L, 1)) {
@ -662,7 +662,7 @@ int l_lovrGraphicsNewFont(lua_State* L) {
int l_lovrGraphicsNewModel(lua_State* L) {
const char* path = lua_tostring(L, 1);
int size;
size_t size;
void* data = lovrFilesystemRead(path, &size);
if (!data) {
return luaL_error(L, "Could not load model file '%s'", path);
@ -688,7 +688,7 @@ int l_lovrGraphicsNewShader(lua_State* L) {
if (lua_isnoneornil(L, i + 1)) continue;
const char* source = luaL_checkstring(L, i + 1);
if (!lovrFilesystemIsFile(source)) continue;
int bytesRead;
size_t bytesRead;
char* contents = lovrFilesystemRead(source, &bytesRead);
if (bytesRead <= 0) {
return luaL_error(L, "Could not read shader from file '%s'", source);
@ -708,7 +708,7 @@ int l_lovrGraphicsNewShader(lua_State* L) {
int l_lovrGraphicsNewSkybox(lua_State* L) {
void* data[6];
int size[6];
size_t size[6];
if (lua_istable(L, 1)) {
if (lua_objlen(L, 1) != 6) {