2017-12-10 20:40:37 +00:00
|
|
|
#include "api.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "filesystem/filesystem.h"
|
2018-02-20 05:04:53 +00:00
|
|
|
#include "data/blob.h"
|
2016-11-02 03:27:15 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2017-04-02 12:55:21 +00:00
|
|
|
// Returns a Blob, leaving stack unchanged. The Blob must be released when finished.
|
|
|
|
Blob* luax_readblob(lua_State* L, int index, const char* debug) {
|
|
|
|
if (lua_type(L, index) == LUA_TUSERDATA) {
|
2017-07-14 14:58:12 +00:00
|
|
|
Blob* blob = luax_checktype(L, index, Blob);
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRetain(blob);
|
2017-04-02 12:55:21 +00:00
|
|
|
return blob;
|
|
|
|
} else {
|
|
|
|
const char* path = luaL_checkstring(L, index);
|
|
|
|
|
|
|
|
size_t size;
|
|
|
|
void* data = lovrFilesystemRead(path, &size);
|
|
|
|
if (!data) {
|
|
|
|
luaL_error(L, "Could not read %s from '%s'", debug, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return lovrBlobCreate(data, size, path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-22 08:37:06 +00:00
|
|
|
static int pushDirectoryItem(void* userdata, const char* path, const char* filename) {
|
2017-03-11 09:37:00 +00:00
|
|
|
lua_State* L = userdata;
|
|
|
|
int n = lua_objlen(L, -1);
|
|
|
|
lua_pushstring(L, filename);
|
|
|
|
lua_rawseti(L, -2, n + 1);
|
2017-10-22 08:37:06 +00:00
|
|
|
return 1;
|
2017-03-11 09:37:00 +00:00
|
|
|
}
|
|
|
|
|
2017-12-31 21:20:42 +00:00
|
|
|
int l_lovrFilesystemLoad(lua_State* L);
|
|
|
|
|
2018-07-07 20:54:53 +00:00
|
|
|
static int moduleLoader(lua_State* L) {
|
2018-03-22 17:07:19 +00:00
|
|
|
const char* module = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
|
2018-03-11 23:25:21 +00:00
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
char* path; int i;
|
|
|
|
vec_foreach(lovrFilesystemGetRequirePath(), path, i) {
|
|
|
|
const char* filename = luaL_gsub(L, path, "?", module);
|
|
|
|
if (lovrFilesystemIsFile(filename)) {
|
|
|
|
return l_lovrFilesystemLoad(L);
|
2016-11-02 03:27:15 +00:00
|
|
|
}
|
2018-03-11 23:25:21 +00:00
|
|
|
lua_pop(L, 1);
|
2016-11-02 03:27:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-11-01 00:14:31 +00:00
|
|
|
|
2018-07-07 20:54:53 +00:00
|
|
|
static const char* libraryExtensions[] = {
|
|
|
|
#ifdef _WIN32
|
|
|
|
".dll", NULL
|
|
|
|
#elif __APPLE__
|
|
|
|
".so", ".dylib", NULL
|
|
|
|
#else
|
|
|
|
".so", NULL
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static int libraryLoader(lua_State* L) {
|
|
|
|
const char* modulePath = luaL_gsub(L, lua_tostring(L, -1), ".", "/");
|
|
|
|
const char* moduleFunction = luaL_gsub(L, lua_tostring(L, -1), ".", "_");
|
|
|
|
lua_pop(L, 3);
|
|
|
|
|
|
|
|
char* path; int i;
|
|
|
|
vec_foreach(lovrFilesystemGetCRequirePath(), path, i) {
|
|
|
|
for (const char** extension = libraryExtensions; *extension != NULL; extension++) {
|
|
|
|
char buffer[64];
|
|
|
|
snprintf(buffer, 63, "%s%s", modulePath, *extension);
|
|
|
|
const char* filename = luaL_gsub(L, path, "??", buffer);
|
|
|
|
filename = luaL_gsub(L, filename, "?", modulePath);
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
if (lovrFilesystemIsFile(filename)) {
|
|
|
|
const char* realPath = lovrFilesystemGetRealDirectory(filename);
|
|
|
|
void* library = lovrLoadLibrary(realPath);
|
|
|
|
|
|
|
|
snprintf(buffer, 63, "luaopen_%s", moduleFunction);
|
|
|
|
void* function = lovrLoadSymbol(library, buffer);
|
|
|
|
if (!function) {
|
|
|
|
snprintf(buffer, 63, "loveopen_%s", moduleFunction);
|
2018-07-07 20:57:32 +00:00
|
|
|
function = lovrLoadSymbol(library, buffer);
|
2018-07-07 20:54:53 +00:00
|
|
|
if (!function) {
|
|
|
|
snprintf(buffer, 63, "lovropen_%s", moduleFunction);
|
2018-07-07 20:57:32 +00:00
|
|
|
function = lovrLoadSymbol(library, buffer);
|
2018-07-07 20:54:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function) {
|
|
|
|
lua_pushcfunction(L, (lua_CFunction) function);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
lovrCloseLibrary(library);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-01 00:14:31 +00:00
|
|
|
int l_lovrFilesystemInit(lua_State* L) {
|
|
|
|
lua_newtable(L);
|
|
|
|
luaL_register(L, NULL, lovrFilesystem);
|
2016-11-02 03:27:15 +00:00
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
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);
|
|
|
|
|
2018-07-07 20:54:53 +00:00
|
|
|
luax_registerloader(L, moduleLoader, 2);
|
|
|
|
luax_registerloader(L, libraryLoader, 3);
|
2016-11-01 00:14:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-07 22:31:11 +00:00
|
|
|
int l_lovrFilesystemAppend(lua_State* L) {
|
|
|
|
size_t size;
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
const char* content = luaL_checklstring(L, 2, &size);
|
2017-03-11 09:37:00 +00:00
|
|
|
lua_pushnumber(L, lovrFilesystemWrite(path, content, size, 1));
|
2016-11-07 22:31:11 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-04-02 22:08:55 +00:00
|
|
|
int l_lovrFilesystemCreateDirectory(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
lua_pushboolean(L, !lovrFilesystemCreateDirectory(path));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
int l_lovrFilesystemGetAppdataDirectory(lua_State* L) {
|
2018-03-19 23:52:17 +00:00
|
|
|
char buffer[LOVR_PATH_MAX];
|
2017-03-11 09:37:00 +00:00
|
|
|
|
2017-03-11 09:45:33 +00:00
|
|
|
if (lovrFilesystemGetAppdataDirectory(buffer, sizeof(buffer))) {
|
2017-03-11 09:37:00 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-11-01 00:14:31 +00:00
|
|
|
int l_lovrFilesystemGetExecutablePath(lua_State* L) {
|
2018-03-19 23:52:17 +00:00
|
|
|
char buffer[LOVR_PATH_MAX];
|
2016-11-01 00:14:31 +00:00
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
if (lovrFilesystemGetExecutablePath(buffer, sizeof(buffer))) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
} else {
|
|
|
|
lua_pushstring(L, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int l_lovrFilesystemGetIdentity(lua_State* L) {
|
2017-06-10 22:34:35 +00:00
|
|
|
const char* identity = lovrFilesystemGetIdentity();
|
|
|
|
if (identity) {
|
|
|
|
lua_pushstring(L, identity);
|
|
|
|
} else {
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
2016-11-07 22:30:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
int l_lovrFilesystemGetRealDirectory(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
2016-11-08 21:45:12 +00:00
|
|
|
lua_pushstring(L, lovrFilesystemGetRealDirectory(path));
|
2016-11-07 22:30:32 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-07-07 04:21:07 +00:00
|
|
|
static void pushRequirePath(lua_State* L, vec_str_t* path) {
|
|
|
|
char* pattern; int i;
|
|
|
|
vec_foreach(path, pattern, i) {
|
|
|
|
lua_pushstring(L, pattern);
|
2018-03-11 23:25:21 +00:00
|
|
|
lua_pushstring(L, ";");
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
2018-07-07 04:21:07 +00:00
|
|
|
lua_concat(L, path->length * 2 - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int l_lovrFilesystemGetRequirePath(lua_State* L) {
|
|
|
|
pushRequirePath(L, lovrFilesystemGetRequirePath());
|
|
|
|
pushRequirePath(L, lovrFilesystemGetCRequirePath());
|
|
|
|
return 2;
|
2018-03-11 23:25:21 +00:00
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
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);
|
2017-10-22 08:37:06 +00:00
|
|
|
size_t size = lovrFilesystemGetSize(path);
|
|
|
|
if ((int) size == -1) {
|
|
|
|
return luaL_error(L, "File does not exist");
|
|
|
|
}
|
|
|
|
lua_pushinteger(L, size);
|
2017-03-11 09:37:00 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
int l_lovrFilesystemGetSource(lua_State* L) {
|
2017-04-02 12:55:21 +00:00
|
|
|
const char* source = lovrFilesystemGetSource();
|
|
|
|
|
|
|
|
if (source) {
|
|
|
|
lua_pushstring(L, source);
|
|
|
|
} else {
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
|
2016-11-01 00:14:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
int l_lovrFilesystemGetUserDirectory(lua_State* L) {
|
|
|
|
lua_pushstring(L, lovrFilesystemGetUserDirectory());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-19 23:52:17 +00:00
|
|
|
int l_lovrFilesystemGetWorkingDirectory(lua_State* L) {
|
|
|
|
char buffer[LOVR_PATH_MAX];
|
|
|
|
|
|
|
|
if (lovrFilesystemGetWorkingDirectory(buffer, sizeof(buffer))) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
} else {
|
|
|
|
lua_pushstring(L, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-01 01:35:00 +00:00
|
|
|
int l_lovrFilesystemIsDirectory(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
lua_pushboolean(L, lovrFilesystemIsDirectory(path));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int l_lovrFilesystemIsFile(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
lua_pushboolean(L, lovrFilesystemIsFile(path));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
int l_lovrFilesystemIsFused(lua_State* L) {
|
|
|
|
lua_pushboolean(L, lovrFilesystemIsFused());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-02 04:08:13 +00:00
|
|
|
int l_lovrFilesystemLoad(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
2017-03-11 09:37:00 +00:00
|
|
|
size_t size;
|
2017-03-02 04:08:13 +00:00
|
|
|
char* content = lovrFilesystemRead(path, &size);
|
|
|
|
|
2017-12-31 21:20:42 +00:00
|
|
|
if (!content) {
|
|
|
|
return luaL_error(L, "Could not read file '%s'", path);
|
|
|
|
}
|
|
|
|
|
2018-04-20 01:38:12 +00:00
|
|
|
char debug[LOVR_PATH_MAX];
|
|
|
|
snprintf(debug, LOVR_PATH_MAX, "@%s", path);
|
|
|
|
|
|
|
|
int status = luaL_loadbuffer(L, content, size, debug);
|
2017-12-31 21:20:42 +00:00
|
|
|
free(content);
|
2017-03-02 04:08:13 +00:00
|
|
|
switch (status) {
|
|
|
|
case LUA_ERRMEM: return luaL_error(L, "Memory allocation error: %s", lua_tostring(L, -1));
|
|
|
|
case LUA_ERRSYNTAX: return luaL_error(L, "Syntax error: %s", lua_tostring(L, -1));
|
|
|
|
default: return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
int l_lovrFilesystemMount(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
const char* mountpoint = luaL_optstring(L, 2, NULL);
|
2017-10-31 08:14:09 +00:00
|
|
|
bool append = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
|
2017-03-11 09:37:00 +00:00
|
|
|
lua_pushboolean(L, !lovrFilesystemMount(path, mountpoint, append));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-04-01 23:50:10 +00:00
|
|
|
int l_lovrFilesystemNewBlob(lua_State* L) {
|
|
|
|
size_t size;
|
2018-02-20 05:04:53 +00:00
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
uint8_t* data = lovrFilesystemRead(path, &size);
|
|
|
|
lovrAssert(data, "Could not load file '%s'", path);
|
2017-04-01 23:50:10 +00:00
|
|
|
Blob* blob = lovrBlobCreate((void*) data, size, path);
|
|
|
|
luax_pushtype(L, Blob, blob);
|
2018-02-26 08:59:03 +00:00
|
|
|
lovrRelease(blob);
|
2017-04-01 23:50:10 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-05 22:55:01 +00:00
|
|
|
int l_lovrFilesystemRead(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
2017-03-11 09:37:00 +00:00
|
|
|
size_t size;
|
2016-11-07 22:30:32 +00:00
|
|
|
char* content = lovrFilesystemRead(path, &size);
|
2018-02-20 05:04:53 +00:00
|
|
|
lovrAssert(content, "Could not read file '%s'", path);
|
2016-11-07 22:30:32 +00:00
|
|
|
lua_pushlstring(L, content, size);
|
2016-11-08 06:23:13 +00:00
|
|
|
free(content);
|
2016-11-05 22:55:01 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
int l_lovrFilesystemRemove(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
lua_pushboolean(L, !lovrFilesystemRemove(path));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-11-07 22:30:32 +00:00
|
|
|
int l_lovrFilesystemSetIdentity(lua_State* L) {
|
2017-06-10 22:34:35 +00:00
|
|
|
if (lua_isnoneornil(L, 1)) {
|
|
|
|
lovrFilesystemSetIdentity(NULL);
|
|
|
|
} else {
|
|
|
|
const char* identity = luaL_checkstring(L, 1);
|
|
|
|
lovrFilesystemSetIdentity(identity);
|
2016-11-01 00:14:31 +00:00
|
|
|
}
|
2016-11-07 22:30:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-11 23:25:21 +00:00
|
|
|
int l_lovrFilesystemSetRequirePath(lua_State* L) {
|
2018-07-07 04:21:07 +00:00
|
|
|
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(luaL_checkstring(L, 1));
|
|
|
|
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(luaL_checkstring(L, 2));
|
2018-03-11 23:25:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-11 09:37:00 +00:00
|
|
|
int l_lovrFilesystemUnmount(lua_State* L) {
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
lua_pushboolean(L, !lovrFilesystemUnmount(path));
|
2016-11-01 00:14:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2016-11-07 22:31:02 +00:00
|
|
|
|
|
|
|
int l_lovrFilesystemWrite(lua_State* L) {
|
|
|
|
size_t size;
|
|
|
|
const char* path = luaL_checkstring(L, 1);
|
|
|
|
const char* content = luaL_checklstring(L, 2, &size);
|
2017-03-11 09:37:00 +00:00
|
|
|
lua_pushnumber(L, lovrFilesystemWrite(path, content, size, 0));
|
2016-11-07 22:31:02 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2017-03-11 11:08:07 +00:00
|
|
|
|
|
|
|
const luaL_Reg lovrFilesystem[] = {
|
|
|
|
{ "append", l_lovrFilesystemAppend },
|
2017-04-02 22:08:55 +00:00
|
|
|
{ "createDirectory", l_lovrFilesystemCreateDirectory },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "getAppdataDirectory", l_lovrFilesystemGetAppdataDirectory },
|
|
|
|
{ "getDirectoryItems", l_lovrFilesystemGetDirectoryItems },
|
|
|
|
{ "getExecutablePath", l_lovrFilesystemGetExecutablePath },
|
|
|
|
{ "getIdentity", l_lovrFilesystemGetIdentity },
|
|
|
|
{ "getLastModified", l_lovrFilesystemGetLastModified },
|
|
|
|
{ "getRealDirectory", l_lovrFilesystemGetRealDirectory },
|
2018-03-11 23:25:21 +00:00
|
|
|
{ "getRequirePath", l_lovrFilesystemGetRequirePath },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "getSaveDirectory", l_lovrFilesystemGetSaveDirectory },
|
|
|
|
{ "getSize", l_lovrFilesystemGetSize },
|
|
|
|
{ "getSource", l_lovrFilesystemGetSource },
|
|
|
|
{ "getUserDirectory", l_lovrFilesystemGetUserDirectory },
|
2018-03-19 23:52:17 +00:00
|
|
|
{ "getWorkingDirectory", l_lovrFilesystemGetWorkingDirectory },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "isDirectory", l_lovrFilesystemIsDirectory },
|
|
|
|
{ "isFile", l_lovrFilesystemIsFile },
|
|
|
|
{ "isFused", l_lovrFilesystemIsFused },
|
|
|
|
{ "load", l_lovrFilesystemLoad },
|
|
|
|
{ "mount", l_lovrFilesystemMount },
|
2017-04-01 23:50:10 +00:00
|
|
|
{ "newBlob", l_lovrFilesystemNewBlob },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "read", l_lovrFilesystemRead },
|
|
|
|
{ "remove", l_lovrFilesystemRemove },
|
2018-03-11 23:25:21 +00:00
|
|
|
{ "setRequirePath", l_lovrFilesystemSetRequirePath },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "setIdentity", l_lovrFilesystemSetIdentity },
|
|
|
|
{ "write", l_lovrFilesystemWrite },
|
|
|
|
{ NULL, NULL }
|
|
|
|
};
|