mirror of
https://github.com/bjornbytes/lovr.git
synced 2024-07-22 21:53:35 +00:00
WIP;
This commit is contained in:
parent
9587dc8532
commit
0ec8cc7c3c
|
@ -160,8 +160,9 @@ static int l_lovrDataNewRasterizer(lua_State* L) {
|
|||
}
|
||||
|
||||
Rasterizer* rasterizer = lovrRasterizerCreate(blob, size, luax_readfile);
|
||||
luax_pushtype(L, Rasterizer, rasterizer);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
luax_assert(L, rasterizer);
|
||||
luax_pushtype(L, Rasterizer, rasterizer);
|
||||
lovrRelease(rasterizer, lovrRasterizerDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ static int luax_loadfile(lua_State* L, const char* path, const char* debug, cons
|
|||
void* buffer = luax_readfile(path, &size);
|
||||
if (!buffer) {
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "Could not load file '%s'", path);
|
||||
lua_pushfstring(L, "Could not read file '%s': %s", path, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
int status = luax_loadbufferx(L, buffer, size, debug, mode);
|
||||
|
@ -92,6 +92,7 @@ static int luax_loadfile(lua_State* L, const char* path, const char* debug, cons
|
|||
|
||||
static int l_lovrFilesystemAppend(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
size_t size;
|
||||
const char* data;
|
||||
Blob* blob = luax_totype(L, 2, Blob);
|
||||
|
@ -103,15 +104,27 @@ static int l_lovrFilesystemAppend(lua_State* L) {
|
|||
} else {
|
||||
return luax_typeerror(L, 2, "string or Blob");
|
||||
}
|
||||
bool success = lovrFilesystemWrite(path, data, size, true);
|
||||
lua_pushboolean(L, success);
|
||||
return 1;
|
||||
|
||||
if (lovrFilesystemWrite(path, data, size, true)) {
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushboolean(L, false);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemCreateDirectory(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, lovrFilesystemCreateDirectory(path));
|
||||
return 1;
|
||||
if (lovrFilesystemCreateDirectory(path)) {
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushboolean(L, false);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemGetAppdataDirectory(lua_State* L) {
|
||||
|
@ -196,15 +209,15 @@ static int l_lovrFilesystemGetIdentity(lua_State* L) {
|
|||
|
||||
static int l_lovrFilesystemGetLastModified(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
uint64_t lastModified = lovrFilesystemGetLastModified(path);
|
||||
|
||||
if (lastModified == ~0ull) {
|
||||
lua_pushnil(L);
|
||||
uint64_t modtime;
|
||||
if (lovrFilesystemGetLastModified(path, &modtime)) {
|
||||
lua_pushinteger(L, modtime);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushinteger(L, lastModified);
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemGetRealDirectory(lua_State* L) {
|
||||
|
@ -225,12 +238,15 @@ static int l_lovrFilesystemGetSaveDirectory(lua_State* L) {
|
|||
|
||||
static int l_lovrFilesystemGetSize(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
uint64_t size = lovrFilesystemGetSize(path);
|
||||
if (size == ~0ull) {
|
||||
return luaL_error(L, "File does not exist"), 0;
|
||||
uint64_t size;
|
||||
if (lovrFilesystemGetSize(path, &size)) {
|
||||
lua_pushinteger(L, size);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
lua_pushinteger(L, size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemGetSource(lua_State* L) {
|
||||
|
@ -299,38 +315,60 @@ static int l_lovrFilesystemMount(lua_State* L) {
|
|||
const char* mountpoint = luaL_optstring(L, 2, NULL);
|
||||
bool append = lua_toboolean(L, 3);
|
||||
const char* root = luaL_optstring(L, 4, NULL);
|
||||
lua_pushboolean(L, lovrFilesystemMount(path, mountpoint, append, root));
|
||||
return 1;
|
||||
bool success = lovrFilesystemMount(path, mountpoint, append, root);
|
||||
if (success) {
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushboolean(L, false);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemNewBlob(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
size_t size;
|
||||
void* data = luax_readfile(path, &size);
|
||||
lovrAssert(data, "Could not load file '%s'", path);
|
||||
Blob* blob = lovrBlobCreate(data, size, path);
|
||||
luax_pushtype(L, Blob, blob);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
return 1;
|
||||
if (data) {
|
||||
Blob* blob = lovrBlobCreate(data, size, path);
|
||||
luax_pushtype(L, Blob, blob);
|
||||
lovrRelease(blob, lovrBlobDestroy);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemRead(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
size_t size;
|
||||
void* data = lovrFilesystemRead(path, &size);
|
||||
if (!data) {
|
||||
lua_pushnil(L);
|
||||
|
||||
if (data) {
|
||||
lua_pushlstring(L, data, size);
|
||||
lovrFree(data);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
lua_pushlstring(L, data, size);
|
||||
lovrFree(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemRemove(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, lovrFilesystemRemove(path));
|
||||
return 1;
|
||||
if (lovrFilesystemRemove(path)) {
|
||||
lua_pushboolean(L, true);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int l_lovrFilesystemSetIdentity(lua_State* L) {
|
||||
|
@ -347,7 +385,7 @@ static int l_lovrFilesystemSetRequirePath(lua_State* L) {
|
|||
|
||||
static int l_lovrFilesystemSetSource(lua_State* L) {
|
||||
const char* source = luaL_checkstring(L, 1);
|
||||
lovrFilesystemSetSource(source);
|
||||
luax_assert(L, lovrFilesystemSetSource(source));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -388,15 +426,14 @@ static int l_lovrFilesystemWrite(lua_State* L) {
|
|||
static int l_lovrFilesystemNewFile(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
OpenMode mode = luax_checkenum(L, 2, OpenMode, NULL);
|
||||
const char* error;
|
||||
File* file = lovrFileCreate(path, mode, &error);
|
||||
File* file = lovrFileCreate(path, mode);
|
||||
if (file) {
|
||||
luax_pushtype(L, File, file);
|
||||
lovrRelease(file, lovrFileDestroy);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, error);
|
||||
lua_pushstring(L, lovrGetError());
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -612,7 +649,7 @@ int luaopen_lovr_filesystem(lua_State* L) {
|
|||
luax_registerloader(L, luaLoader, 2);
|
||||
luax_registerloader(L, libLoader, 3);
|
||||
luax_registerloader(L, libLoaderAllInOne, 4);
|
||||
lovrFilesystemInit();
|
||||
luax_assert(L, lovrFilesystemInit());
|
||||
luax_atexit(L, lovrFilesystemDestroy);
|
||||
return 1;
|
||||
}
|
||||
|
|
133
src/core/fs.c
133
src/core/fs.c
|
@ -190,8 +190,31 @@ bool fs_list(const char* path, fs_list_cb* callback, void* context) {
|
|||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
bool fs_open(const char* path, char mode, fs_handle* file) {
|
||||
static int check(int result) {
|
||||
if (result < 0) {
|
||||
switch (errno) {
|
||||
case EACCES: return FS_PERMISSION;
|
||||
case EPERM: return FS_PERMISSION;
|
||||
case EROFS: return FS_READ_ONLY;
|
||||
case EEXIST: return FS_EXISTS;
|
||||
case ENOENT: return FS_NOT_FOUND;
|
||||
case EDQUOT: return FS_NO_SPACE;
|
||||
case ENOSPC: return FS_NO_SPACE;
|
||||
case ENOTDIR: return FS_NOT_DIR;
|
||||
case EISDIR: return FS_IS_DIR;
|
||||
case ELOOP: return FS_LOOP;
|
||||
case ETXTBSY: return FS_BUSY;
|
||||
case EIO: return FS_IO;
|
||||
default: return FS_UNKNOWN_ERROR;
|
||||
}
|
||||
} else {
|
||||
return FS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
int fs_open(const char* path, char mode, fs_handle* file) {
|
||||
int flags;
|
||||
switch (mode) {
|
||||
case 'r': flags = O_RDONLY; break;
|
||||
|
@ -199,94 +222,104 @@ bool fs_open(const char* path, char mode, fs_handle* file) {
|
|||
case 'a': flags = O_APPEND | O_WRONLY | O_CREAT; break;
|
||||
default: return false;
|
||||
}
|
||||
struct stat stats;
|
||||
file->fd = open(path, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
||||
return file->fd >= 0 && !fstat(file->fd, &stats) && !S_ISDIR(stats.st_mode);
|
||||
return check(file->fd);
|
||||
}
|
||||
|
||||
bool fs_close(fs_handle file) {
|
||||
return close(file.fd) == 0;
|
||||
int fs_close(fs_handle file) {
|
||||
return check(close(file.fd));
|
||||
}
|
||||
|
||||
bool fs_read(fs_handle file, void* data, size_t size, size_t* count) {
|
||||
int fs_read(fs_handle file, void* data, size_t size, size_t* count) {
|
||||
ssize_t result = read(file.fd, data, size);
|
||||
if (result < 0 || result > SSIZE_MAX) {
|
||||
if (result < 0) {
|
||||
*count = 0;
|
||||
return false;
|
||||
return check(result);
|
||||
} else {
|
||||
*count = result;
|
||||
return true;
|
||||
return FS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
bool fs_write(fs_handle file, const void* data, size_t size, size_t* count) {
|
||||
int fs_write(fs_handle file, const void* data, size_t size, size_t* count) {
|
||||
ssize_t result = write(file.fd, data, size);
|
||||
if (result < 0 || result > SSIZE_MAX) {
|
||||
if (result < 0) {
|
||||
*count = 0;
|
||||
return false;
|
||||
return check(result);
|
||||
} else {
|
||||
*count = (size_t) result;
|
||||
return true;
|
||||
*count = result;
|
||||
return FS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
bool fs_seek(fs_handle file, uint64_t offset) {
|
||||
return lseek(file.fd, (off_t) offset, SEEK_SET) != (off_t) -1;
|
||||
int fs_seek(fs_handle file, uint64_t offset) {
|
||||
return check(lseek(file.fd, (off_t) offset, SEEK_SET));
|
||||
}
|
||||
|
||||
bool fs_fstat(fs_handle file, FileInfo* info) {
|
||||
int fs_fstat(fs_handle file, FileInfo* info) {
|
||||
struct stat stats;
|
||||
if (fstat(file.fd, &stats)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = fstat(file.fd, &stats);
|
||||
info->size = (uint64_t) stats.st_size;
|
||||
info->lastModified = (uint64_t) stats.st_mtime;
|
||||
info->type = S_ISDIR(stats.st_mode) ? FILE_DIRECTORY : FILE_REGULAR;
|
||||
return true;
|
||||
return check(result);
|
||||
}
|
||||
|
||||
void* fs_map(const char* path, size_t* size) {
|
||||
int fs_map(const char* path, void** pointer, size_t* size) {
|
||||
int error;
|
||||
|
||||
FileInfo info;
|
||||
if ((error = fs_stat(path, &info)) != FS_OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
fs_handle file;
|
||||
if (!fs_stat(path, &info) || !fs_open(path, 'r', &file)) {
|
||||
return NULL;
|
||||
if ((error = fs_open(path, 'r', &file)) != FS_OK) {
|
||||
return error;
|
||||
}
|
||||
|
||||
*pointer = mmap(NULL, info.size, PROT_READ, MAP_PRIVATE, file.fd, 0);
|
||||
*size = info.size;
|
||||
void* data = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, file.fd, 0);
|
||||
fs_close(file);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool fs_unmap(void* data, size_t size) {
|
||||
return munmap(data, size) == 0;
|
||||
}
|
||||
|
||||
bool fs_stat(const char* path, FileInfo* info) {
|
||||
struct stat stats;
|
||||
if (stat(path, &stats)) {
|
||||
return false;
|
||||
if (*pointer == MAP_FAILED) {
|
||||
return check(-1);
|
||||
}
|
||||
|
||||
return FS_OK;
|
||||
}
|
||||
|
||||
int fs_unmap(void* data, size_t size) {
|
||||
return check(munmap(data, size));
|
||||
}
|
||||
|
||||
int fs_stat(const char* path, FileInfo* info) {
|
||||
struct stat stats;
|
||||
int result = stat(path, &stats);
|
||||
info->size = (uint64_t) stats.st_size;
|
||||
info->lastModified = (uint64_t) stats.st_mtime;
|
||||
info->type = S_ISDIR(stats.st_mode) ? FILE_DIRECTORY : FILE_REGULAR;
|
||||
return true;
|
||||
return check(result);
|
||||
}
|
||||
|
||||
bool fs_remove(const char* path) {
|
||||
return unlink(path) == 0 || rmdir(path) == 0;
|
||||
}
|
||||
|
||||
bool fs_mkdir(const char* path) {
|
||||
return mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0;
|
||||
}
|
||||
|
||||
bool fs_list(const char* path, fs_list_cb* callback, void* context) {
|
||||
DIR* dir = opendir(path);
|
||||
if (!dir) {
|
||||
return false;
|
||||
int fs_remove(const char* path) {
|
||||
if (unlink(path)) {
|
||||
if (errno == EISDIR) {
|
||||
return check(rmdir(path));
|
||||
} else {
|
||||
return check(-1);
|
||||
}
|
||||
}
|
||||
return FS_OK;
|
||||
}
|
||||
|
||||
int fs_mkdir(const char* path) {
|
||||
return check(mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH));
|
||||
}
|
||||
|
||||
int fs_list(const char* path, fs_list_cb* callback, void* context) {
|
||||
DIR* dir = opendir(path);
|
||||
if (!dir) return check(-1);
|
||||
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
|
@ -294,7 +327,7 @@ bool fs_list(const char* path, fs_list_cb* callback, void* context) {
|
|||
}
|
||||
|
||||
closedir(dir);
|
||||
return true;
|
||||
return FS_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,21 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
FS_OK,
|
||||
FS_UNKNOWN_ERROR,
|
||||
FS_PERMISSION,
|
||||
FS_READ_ONLY,
|
||||
FS_NOT_FOUND,
|
||||
FS_EXISTS,
|
||||
FS_IS_DIR,
|
||||
FS_NOT_DIR,
|
||||
FS_LOOP,
|
||||
FS_NO_SPACE,
|
||||
FS_BUSY,
|
||||
FS_IO
|
||||
} FileError;
|
||||
|
||||
typedef enum {
|
||||
FILE_DIRECTORY,
|
||||
FILE_REGULAR
|
||||
|
@ -18,15 +33,15 @@ typedef struct {
|
|||
typedef void fs_list_cb(void*, const char*);
|
||||
typedef union { int fd; void* handle; } fs_handle;
|
||||
|
||||
bool fs_open(const char* path, char mode, fs_handle* file);
|
||||
bool fs_close(fs_handle file);
|
||||
bool fs_read(fs_handle file, void* data, size_t size, size_t* count);
|
||||
bool fs_write(fs_handle file, const void* data, size_t size, size_t* count);
|
||||
bool fs_seek(fs_handle file, uint64_t offset);
|
||||
bool fs_fstat(fs_handle file, FileInfo* info);
|
||||
void* fs_map(const char* path, size_t* size);
|
||||
bool fs_unmap(void* data, size_t size);
|
||||
bool fs_stat(const char* path, FileInfo* info);
|
||||
bool fs_remove(const char* path);
|
||||
bool fs_mkdir(const char* path);
|
||||
bool fs_list(const char* path, fs_list_cb* callback, void* context);
|
||||
int fs_open(const char* path, char mode, fs_handle* file);
|
||||
int fs_close(fs_handle file);
|
||||
int fs_read(fs_handle file, void* data, size_t size, size_t* count);
|
||||
int fs_write(fs_handle file, const void* data, size_t size, size_t* count);
|
||||
int fs_seek(fs_handle file, uint64_t offset);
|
||||
int fs_fstat(fs_handle file, FileInfo* info);
|
||||
int fs_map(const char* path, void** pointer, size_t* size);
|
||||
int fs_unmap(void* data, size_t size);
|
||||
int fs_stat(const char* path, FileInfo* info);
|
||||
int fs_remove(const char* path);
|
||||
int fs_mkdir(const char* path);
|
||||
int fs_list(const char* path, fs_list_cb* callback, void* context);
|
||||
|
|
|
@ -41,17 +41,17 @@ static Glyph* lovrRasterizerGetGlyph(Rasterizer* rasterizer, uint32_t codepoint)
|
|||
return index == MAP_NIL ? NULL : &rasterizer->glyphs.data[index];
|
||||
}
|
||||
|
||||
static Rasterizer* lovrRasterizerCreateTTF(Blob* blob, float size) {
|
||||
static bool lovrRasterizerCreateTTF(Rasterizer** result, Blob* blob, float size) {
|
||||
const unsigned char* data = blob ? blob->data : etc_VarelaRound_ttf;
|
||||
|
||||
int offset = stbtt_GetFontOffsetForIndex(data, 0);
|
||||
if (offset == -1) {
|
||||
return NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
stbtt_fontinfo font;
|
||||
if (!stbtt_InitFont(&font, data, offset)) {
|
||||
return NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Rasterizer* rasterizer = lovrCalloc(sizeof(Rasterizer));
|
||||
|
@ -73,7 +73,8 @@ static Rasterizer* lovrRasterizerCreateTTF(Blob* blob, float size) {
|
|||
|
||||
map_init(&rasterizer->kerning, 0);
|
||||
|
||||
return rasterizer;
|
||||
*result = rasterizer;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int64_t parseNumber(const char* string, size_t length, map_t* map, const char* key) {
|
||||
|
@ -115,17 +116,25 @@ static int16_t readi16(const uint8_t* p) { int16_t x; memcpy(&x, p, sizeof(x));
|
|||
static uint16_t readu16(const uint8_t* p) { uint16_t x; memcpy(&x, p, sizeof(x)); return x; }
|
||||
static uint32_t readu32(const uint8_t* p) { uint32_t x; memcpy(&x, p, sizeof(x)); return x; }
|
||||
|
||||
static Rasterizer* lovrRasterizerCreateBMF(Blob* blob, RasterizerIO* io) {
|
||||
if (!blob || blob->size < 4) return NULL;
|
||||
static bool lovrRasterizerCreateBMF(Rasterizer** result, Blob* blob, RasterizerIO* io) {
|
||||
if (!blob || blob->size < 4) return true;
|
||||
|
||||
uint8_t magic[] = { 'B', 'M', 'F' };
|
||||
bool text = !memcmp(blob->data, "info", 4);
|
||||
bool binary = !memcmp(blob->data, magic, sizeof(magic));
|
||||
|
||||
if (!text && !binary) {
|
||||
return NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
char fullpath[1024];
|
||||
size_t nameLength = strlen(blob->name);
|
||||
lovrCheck(nameLength < sizeof(fullpath), "BMFont Blob filename is too long");
|
||||
memcpy(fullpath, blob->name, nameLength + 1);
|
||||
char* slash = strrchr(fullpath, '/');
|
||||
char* filename = slash ? slash + 1 : fullpath;
|
||||
size_t maxLength = sizeof(fullpath) - 1 - (filename - fullpath);
|
||||
|
||||
Rasterizer* rasterizer = lovrCalloc(sizeof(Rasterizer));
|
||||
rasterizer->ref = 1;
|
||||
rasterizer->type = RASTERIZER_BMF;
|
||||
|
@ -135,14 +144,6 @@ static Rasterizer* lovrRasterizerCreateBMF(Blob* blob, RasterizerIO* io) {
|
|||
arr_reserve(&rasterizer->glyphs, 36);
|
||||
map_init(&rasterizer->glyphLookup, 36);
|
||||
|
||||
char fullpath[1024];
|
||||
size_t nameLength = strlen(blob->name);
|
||||
lovrCheck(nameLength < sizeof(fullpath), "BMFont Blob filename is too long");
|
||||
memcpy(fullpath, blob->name, nameLength + 1);
|
||||
char* slash = strrchr(fullpath, '/');
|
||||
char* filename = slash ? slash + 1 : fullpath;
|
||||
size_t maxLength = sizeof(fullpath) - 1 - (filename - fullpath);
|
||||
|
||||
if (text) {
|
||||
map_t map;
|
||||
map_init(&map, 8);
|
||||
|
@ -184,11 +185,21 @@ static Rasterizer* lovrRasterizerCreateBMF(Blob* blob, RasterizerIO* io) {
|
|||
if (!memcmp(tag, "info", tagLength)) {
|
||||
rasterizer->size = parseNumber(string, lineLength, &map, "size");
|
||||
} else if (!memcmp(tag, "common", tagLength)) {
|
||||
lovrCheck(parseNumber(string, lineLength, &map, "pages") == 1, "Currently, BMFont files with multiple images are not supported");
|
||||
lovrCheck(parseNumber(string, lineLength, &map, "packed") == 0, "Currently, packed BMFont files are not supported");
|
||||
rasterizer->leading = parseNumber(string, lineLength, &map, "lineHeight");
|
||||
rasterizer->ascent = parseNumber(string, lineLength, &map, "base");
|
||||
rasterizer->descent = rasterizer->leading - rasterizer->ascent; // Best effort
|
||||
|
||||
if (parseNumber(string, lineLength, &map, "pages") != 1) {
|
||||
lovrSetError("Currently, BMFont files with multiple images are not supported");
|
||||
map_free(&map);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (parseNumber(string, lineLength, &map, "packed") != 0) {
|
||||
lovrSetError("Currently, packed BMFont files are not supported");
|
||||
map_free(&map);
|
||||
goto fail;
|
||||
}
|
||||
} else if (!memcmp(tag, "page", tagLength)) {
|
||||
size_t fileLength;
|
||||
const char* file = parseString(string, lineLength, &map, "file", &fileLength);
|
||||
|
@ -293,19 +304,36 @@ static Rasterizer* lovrRasterizerCreateBMF(Blob* blob, RasterizerIO* io) {
|
|||
|
||||
size_t atlasSize;
|
||||
void* atlasData = io(fullpath, &atlasSize);
|
||||
lovrCheck(atlasData, "Failed to read BMFont image from %s", fullpath);
|
||||
|
||||
if (!atlasData) {
|
||||
lovrSetError("Failed to read BMFont image from %s", fullpath);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Blob* atlasBlob = lovrBlobCreate(atlasData, atlasSize, "BMFont atlas");
|
||||
rasterizer->atlas = lovrImageCreateFromFile(atlasBlob);
|
||||
lovrRelease(atlasBlob, lovrBlobDestroy);
|
||||
|
||||
return rasterizer;
|
||||
if (!rasterizer->atlas) {
|
||||
lovrSetError("Failed to load BMFont atlas image: %s", lovrGetError());
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*result = rasterizer;
|
||||
return true;
|
||||
fail:
|
||||
map_free(&rasterizer->kerning);
|
||||
arr_free(&rasterizer->glyphs);
|
||||
map_free(&rasterizer->glyphLookup);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rasterizer* lovrRasterizerCreate(Blob* blob, float size, RasterizerIO* io) {
|
||||
Rasterizer* rasterizer = NULL;
|
||||
if ((rasterizer = lovrRasterizerCreateTTF(blob, size)) != NULL) return rasterizer;
|
||||
if ((rasterizer = lovrRasterizerCreateBMF(blob, io)) != NULL) return rasterizer;
|
||||
lovrThrow("Problem loading font: not recognized as TTF or BMFont");
|
||||
return NULL;
|
||||
if (!rasterizer && !lovrRasterizerCreateTTF(&rasterizer, blob, size)) return NULL;
|
||||
if (!rasterizer && !lovrRasterizerCreateBMF(&rasterizer, blob, io)) return NULL;
|
||||
if (!rasterizer) lovrSetError("Problem loading font: not recognized as TTF or BMFont");
|
||||
return rasterizer;
|
||||
}
|
||||
|
||||
void lovrRasterizerDestroy(void* ref) {
|
||||
|
@ -532,7 +560,7 @@ bool lovrRasterizerGetPixels(Rasterizer* rasterizer, uint32_t codepoint, float*
|
|||
int id = stbtt_FindGlyphIndex(&rasterizer->font, codepoint);
|
||||
|
||||
if (!id || stbtt_IsGlyphEmpty(&rasterizer->font, id)) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
stbtt_vertex* vertices;
|
||||
|
|
|
@ -80,14 +80,32 @@ static struct {
|
|||
size_t savePathLength;
|
||||
char savePath[1024];
|
||||
char source[1024];
|
||||
char requirePath[1024];
|
||||
char* requirePath;
|
||||
char identity[64];
|
||||
} state;
|
||||
|
||||
static bool checkfs(int result) {
|
||||
switch (result) {
|
||||
case FS_OK: return true;
|
||||
case FS_UNKNOWN_ERROR: lovrSetError("unknown error"); return false;
|
||||
case FS_PERMISSION: lovrSetError("permission denied"); return false;
|
||||
case FS_READ_ONLY: lovrSetError("read only"); return false;
|
||||
case FS_NOT_FOUND: lovrSetError("not found"); return false;
|
||||
case FS_EXISTS: lovrSetError("already exists"); return false;
|
||||
case FS_IS_DIR: lovrSetError("is directory"); return false;
|
||||
case FS_NOT_DIR: lovrSetError("not a directory"); return false;
|
||||
case FS_LOOP: lovrSetError("symlink loop"); return false;
|
||||
case FS_NO_SPACE: lovrSetError("out of space"); return false;
|
||||
case FS_BUSY: lovrSetError("busy"); return false;
|
||||
case FS_IO: lovrSetError("io error"); return false;
|
||||
default: lovrUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
// Rejects any path component that would escape the virtual filesystem (./, ../, :, and \)
|
||||
static bool valid(const char* path) {
|
||||
if (path[0] == '.' && (path[1] == '\0' || path[1] == '.')) {
|
||||
return false;
|
||||
return lovrSetError("Invalid path");
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -97,7 +115,7 @@ static bool valid(const char* path) {
|
|||
(*path == '/' && path[1] == '.' &&
|
||||
(path[2] == '.' ? (path[3] == '/' || path[3] == '\0') : (path[2] == '/' || path[2] == '\0')))
|
||||
) {
|
||||
return false;
|
||||
return lovrSetError("Invalid path");
|
||||
}
|
||||
} while (*path++ != '\0');
|
||||
|
||||
|
@ -106,7 +124,7 @@ static bool valid(const char* path) {
|
|||
|
||||
// Does not work with empty strings
|
||||
static bool concat(char* buffer, const char* p1, size_t length1, const char* p2, size_t length2) {
|
||||
if (length1 + 1 + length2 >= LOVR_PATH_MAX) return false;
|
||||
if (length1 + 1 + length2 >= LOVR_PATH_MAX) return lovrSetError("Path is too long");
|
||||
memcpy(buffer + length1 + 1, p2, length2);
|
||||
buffer[length1 + 1 + length2] = '\0';
|
||||
memcpy(buffer, p1, length1);
|
||||
|
@ -133,13 +151,13 @@ static size_t normalize(const char* path, size_t length, char* buffer) {
|
|||
static bool sanitize(const char* path, char* buffer, size_t* length) {
|
||||
if (!valid(path)) return false;
|
||||
size_t pathLength = strlen(path);
|
||||
if (pathLength >= *length) return false;
|
||||
if (pathLength >= *length) return lovrSetError("Path is too long");
|
||||
*length = normalize(path, pathLength, buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lovrFilesystemInit(void) {
|
||||
if (atomic_fetch_add(&state.ref, 1)) return false;
|
||||
if (atomic_fetch_add(&state.ref, 1)) return true;
|
||||
|
||||
lovrFilesystemSetRequirePath("?.lua;?/init.lua");
|
||||
|
||||
|
@ -177,15 +195,17 @@ void lovrFilesystemDestroy(void) {
|
|||
archive = next;
|
||||
}
|
||||
lovrFilesystemUnwatch();
|
||||
lovrFree(state.requirePath);
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
void lovrFilesystemSetSource(const char* source) {
|
||||
bool lovrFilesystemSetSource(const char* source) {
|
||||
lovrCheck(!state.source[0], "Source is already set!");
|
||||
size_t length = strlen(source);
|
||||
lovrCheck(sizeof(state.source) > length, "Source is too long!");
|
||||
memcpy(state.source, source, length);
|
||||
state.source[length] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* lovrFilesystemGetSource(void) {
|
||||
|
@ -225,7 +245,7 @@ void lovrFilesystemWatch(void) {
|
|||
const char* path = state.source;
|
||||
#endif
|
||||
FileInfo info;
|
||||
if (!watcher.id && fs_stat(path, &info) && info.type == FILE_DIRECTORY) {
|
||||
if (!watcher.id && fs_stat(path, &info) == FS_OK && info.type == FILE_DIRECTORY) {
|
||||
dmon_init();
|
||||
watcher = dmon_watch(path, onFileEvent, DMON_WATCHFLAGS_RECURSIVE, NULL);
|
||||
}
|
||||
|
@ -250,6 +270,7 @@ bool lovrFilesystemIsFused(void) {
|
|||
bool lovrFilesystemMount(const char* path, const char* mountpoint, bool append, const char* root) {
|
||||
FOREACH_ARCHIVE(archive) {
|
||||
if (!strcmp(archive->path, path)) {
|
||||
lovrSetError("Already mounted");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -300,6 +321,8 @@ static Archive* archiveStat(const char* p, FileInfo* info, bool needTime) {
|
|||
if (archiveContains(archive, path, length)) {
|
||||
if (archive->stat(archive, path, info, needTime)) {
|
||||
return archive;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else if (mountpointContains(archive, path, length)) {
|
||||
info->type = FILE_DIRECTORY;
|
||||
|
@ -308,7 +331,11 @@ static Archive* archiveStat(const char* p, FileInfo* info, bool needTime) {
|
|||
return archive;
|
||||
}
|
||||
}
|
||||
|
||||
lovrSetError("File not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -333,9 +360,14 @@ uint64_t lovrFilesystemGetSize(const char* path) {
|
|||
return archiveStat(path, &info, false) && info.type == FILE_REGULAR ? info.size : 0;
|
||||
}
|
||||
|
||||
uint64_t lovrFilesystemGetLastModified(const char* path) {
|
||||
bool lovrFilesystemGetLastModified(const char* path, uint64_t* modtime) {
|
||||
FileInfo info;
|
||||
return archiveStat(path, &info, true) ? info.lastModified : ~0ull;
|
||||
if (archiveStat(path, &info, true)) {
|
||||
*modtime = info.lastModified;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void* lovrFilesystemRead(const char* p, size_t* size) {
|
||||
|
@ -349,13 +381,19 @@ void* lovrFilesystemRead(const char* p, size_t* size) {
|
|||
}
|
||||
|
||||
if (!archive->open(archive, path, &handle)) {
|
||||
continue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t bytes;
|
||||
if (!archive->fsize(archive, &handle, &bytes) || bytes > SIZE_MAX) {
|
||||
if (!archive->fsize(archive, &handle, &bytes)) {
|
||||
archive->close(archive, &handle);
|
||||
continue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bytes > SIZE_MAX) {
|
||||
archive->close(archive, &handle);
|
||||
lovrSetError("File is too big");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size = (size_t) bytes;
|
||||
|
@ -364,10 +402,14 @@ void* lovrFilesystemRead(const char* p, size_t* size) {
|
|||
if (archive->read(archive, &handle, data, *size, size)) {
|
||||
archive->close(archive, &handle);
|
||||
return data;
|
||||
} else {
|
||||
archive->close(archive, &handle);
|
||||
lovrFree(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
archive->close(archive, &handle);
|
||||
}
|
||||
|
||||
lovrSetError("File not found");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -401,8 +443,13 @@ const char* lovrFilesystemGetIdentity(void) {
|
|||
bool lovrFilesystemSetIdentity(const char* identity, bool precedence) {
|
||||
size_t length = strlen(identity);
|
||||
|
||||
// Identity can only be set once, and can't be empty
|
||||
if (state.identity[0] != '\0' || length == 0) {
|
||||
if (state.identity[0] != '\0') {
|
||||
lovrSetError("Identity is already set");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
lovrSetError("Identity can not be empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -411,11 +458,13 @@ bool lovrFilesystemSetIdentity(const char* identity, bool precedence) {
|
|||
|
||||
// If the data path was too long or unavailable, fail
|
||||
if (cursor == 0) {
|
||||
lovrSetError("Could not get appdata path");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure there is enough room to tack on /LOVR/<identity>
|
||||
if (cursor + 1 + strlen("LOVR") + 1 + length >= sizeof(state.savePath)) {
|
||||
lovrSetError("Identity path is too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -433,14 +482,15 @@ bool lovrFilesystemSetIdentity(const char* identity, bool precedence) {
|
|||
|
||||
// mkdir -p
|
||||
FileInfo info;
|
||||
if (!fs_stat(state.savePath, &info)) {
|
||||
if (fs_stat(state.savePath, &info) != FS_OK) {
|
||||
for (char* slash = strchr(state.savePath, SLASH); slash; slash = strchr(slash + 1, SLASH)) {
|
||||
*slash = '\0';
|
||||
fs_mkdir(state.savePath);
|
||||
*slash = SLASH;
|
||||
}
|
||||
|
||||
if (!fs_mkdir(state.savePath)) {
|
||||
if (!checkfs(fs_mkdir(state.savePath))) {
|
||||
lovrSetError("Failed to create identity folder: %s", lovrGetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +513,6 @@ const char* lovrFilesystemGetSaveDirectory(void) {
|
|||
|
||||
bool lovrFilesystemCreateDirectory(const char* path) {
|
||||
char resolved[LOVR_PATH_MAX];
|
||||
|
||||
if (!valid(path) || !concat(resolved, state.savePath, state.savePathLength, path, strlen(path))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -480,12 +529,16 @@ bool lovrFilesystemCreateDirectory(const char* path) {
|
|||
cursor++;
|
||||
}
|
||||
|
||||
return fs_mkdir(resolved);
|
||||
return checkfs(fs_mkdir(resolved));
|
||||
}
|
||||
|
||||
bool lovrFilesystemRemove(const char* path) {
|
||||
char resolved[LOVR_PATH_MAX];
|
||||
return valid(path) && concat(resolved, state.savePath, state.savePathLength, path, strlen(path)) && fs_remove(resolved);
|
||||
if (!valid(path) || !concat(resolved, state.savePath, state.savePathLength, path, strlen(path))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkfs(fs_remove(resolved));
|
||||
}
|
||||
|
||||
bool lovrFilesystemWrite(const char* path, const char* content, size_t size, bool append) {
|
||||
|
@ -495,16 +548,21 @@ bool lovrFilesystemWrite(const char* path, const char* content, size_t size, boo
|
|||
}
|
||||
|
||||
fs_handle file;
|
||||
if (!fs_open(resolved, append ? 'a' : 'w', &file)) {
|
||||
if (!checkfs(fs_open(resolved, append ? 'a' : 'w', &file))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t count;
|
||||
if (!fs_write(file, content, size, &count) || count != size) {
|
||||
if (!checkfs(fs_write(file, content, size, &count))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fs_close(file);
|
||||
if (count != size) {
|
||||
lovrSetError("Incomplete write");
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkfs(fs_close(file));
|
||||
}
|
||||
|
||||
// Paths
|
||||
|
@ -535,9 +593,9 @@ const char* lovrFilesystemGetRequirePath(void) {
|
|||
|
||||
void lovrFilesystemSetRequirePath(const char* requirePath) {
|
||||
size_t length = strlen(requirePath);
|
||||
lovrCheck(length < sizeof(state.requirePath), "Require path is too long");
|
||||
memcpy(state.requirePath, requirePath, length);
|
||||
state.requirePath[length] = '\0';
|
||||
lovrFree(state.requirePath);
|
||||
state.requirePath = lovrMalloc(length + 1);
|
||||
memcpy(state.requirePath, requirePath, length + 1);
|
||||
}
|
||||
|
||||
// Archive: dir
|
||||
|
@ -549,48 +607,49 @@ static bool dir_resolve(Archive* archive, const char* fullpath, char* buffer) {
|
|||
|
||||
static bool dir_init(Archive* archive, const char* path, const char* root) {
|
||||
FileInfo info;
|
||||
return fs_stat(path, &info) && info.type == FILE_DIRECTORY;
|
||||
return checkfs(fs_stat(path, &info)) && info.type == FILE_DIRECTORY;
|
||||
}
|
||||
|
||||
static bool dir_open(Archive* archive, const char* path, Handle* handle) {
|
||||
char resolved[LOVR_PATH_MAX];
|
||||
return dir_resolve(archive, path, resolved) && fs_open(resolved, 'r', &handle->file);
|
||||
return dir_resolve(archive, path, resolved) && checkfs(fs_open(resolved, 'r', &handle->file));
|
||||
}
|
||||
|
||||
static bool dir_close(Archive* archive, Handle* handle) {
|
||||
return fs_close(handle->file);
|
||||
return checkfs(fs_close(handle->file));
|
||||
}
|
||||
|
||||
static bool dir_read(Archive* archive, Handle* handle, uint8_t* data, size_t size, size_t* count) {
|
||||
if (!fs_read(handle->file, data, size, count)) {
|
||||
return false;
|
||||
} else {
|
||||
if (checkfs(fs_read(handle->file, data, size, count))) {
|
||||
handle->offset += *count;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool dir_seek(Archive* archive, Handle* handle, uint64_t offset) {
|
||||
if (fs_seek(handle->file, offset)) {
|
||||
if (checkfs(fs_seek(handle->file, offset))) {
|
||||
handle->offset = offset;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool dir_fsize(Archive* archive, Handle* handle, uint64_t* size) {
|
||||
FileInfo info;
|
||||
if (!fs_fstat(handle->file, &info)) {
|
||||
return false;
|
||||
} else {
|
||||
if (checkfs(fs_fstat(handle->file, &info))) {
|
||||
*size = info.size;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool dir_stat(Archive* archive, const char* path, FileInfo* info, bool needTime) {
|
||||
char resolved[LOVR_PATH_MAX];
|
||||
return dir_resolve(archive, path, resolved) && fs_stat(resolved, info);
|
||||
return dir_resolve(archive, path, resolved) && checkfs(fs_stat(resolved, info));
|
||||
}
|
||||
|
||||
static void dir_list(Archive* archive, const char* path, fs_list_cb callback, void* context) {
|
||||
|
@ -613,9 +672,7 @@ static void zip_free(Archive* archive) {
|
|||
|
||||
static bool zip_init(Archive* archive, const char* filename, const char* root) {
|
||||
// Map the zip file into memory
|
||||
archive->data = fs_map(filename, &archive->size);
|
||||
if (!archive->data) {
|
||||
zip_free(archive);
|
||||
if (!checkfs(fs_map(filename, (void**) &archive->data, &archive->size))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -886,6 +943,7 @@ static bool zip_read(Archive* archive, Handle* handle, uint8_t* data, size_t siz
|
|||
}
|
||||
|
||||
if (!decompress(node, stream, NULL, handle->offset - stream->outputCursor, NULL)) {
|
||||
lovrSetError("Could not decompress file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -912,6 +970,7 @@ static bool zip_read(Archive* archive, Handle* handle, uint8_t* data, size_t siz
|
|||
return true;
|
||||
}
|
||||
|
||||
lovrSetError("Could not decompress file");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1011,11 +1070,11 @@ void lovrArchiveDestroy(void* ref) {
|
|||
|
||||
// File
|
||||
|
||||
File* lovrFileCreate(const char* p, OpenMode mode, const char** error) {
|
||||
File* lovrFileCreate(const char* p, OpenMode mode) {
|
||||
char path[1024];
|
||||
size_t length = sizeof(path);
|
||||
if (!sanitize(p, path, &length)) {
|
||||
return *error = "File path is too long or contains invalid characters", NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Handle handle = { 0 };
|
||||
|
@ -1024,24 +1083,23 @@ File* lovrFileCreate(const char* p, OpenMode mode, const char** error) {
|
|||
if (mode == OPEN_READ) {
|
||||
FOREACH_ARCHIVE(a) {
|
||||
if (archiveContains(a, path, length)) {
|
||||
if (a->open(a, path, &handle)) {
|
||||
archive = a;
|
||||
break;
|
||||
if (!a->open(a, path, &handle)) {
|
||||
return NULL;
|
||||
}
|
||||
archive = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!archive) {
|
||||
return *error = "File does not exist", NULL;
|
||||
}
|
||||
lovrAssert(archive, "File not found");
|
||||
} else {
|
||||
char fullpath[LOVR_PATH_MAX];
|
||||
if (!concat(fullpath, state.savePath, state.savePathLength, path, length)) {
|
||||
return *error = "File path is too long", NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!fs_open(fullpath, mode == OPEN_APPEND ? 'a' : 'w', &handle.file)) {
|
||||
return *error = "Failed to open file for writing", NULL; // TODO better errors pl0x
|
||||
if (!checkfs(fs_open(fullpath, mode == OPEN_APPEND ? 'a' : 'w', &handle.file))) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1050,11 +1108,9 @@ File* lovrFileCreate(const char* p, OpenMode mode, const char** error) {
|
|||
file->mode = mode;
|
||||
file->handle = handle;
|
||||
file->archive = archive;
|
||||
lovrRetain(archive);
|
||||
|
||||
file->path = lovrMalloc(length + 1);
|
||||
memcpy(file->path, path, length + 1);
|
||||
|
||||
lovrRetain(archive);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
@ -1074,9 +1130,8 @@ OpenMode lovrFileGetMode(File* file) {
|
|||
return file->mode;
|
||||
}
|
||||
|
||||
uint64_t lovrFileGetSize(File* file) {
|
||||
uint64_t size;
|
||||
return file->archive->fsize(file->archive, &file->handle, &size) ? size : ~0ull;
|
||||
bool lovrFileGetSize(File* file, uint64_t* size) {
|
||||
return file->archive->fsize(file->archive, &file->handle, &size);
|
||||
}
|
||||
|
||||
bool lovrFileRead(File* file, void* data, size_t size, size_t* count) {
|
||||
|
@ -1086,7 +1141,7 @@ bool lovrFileRead(File* file, void* data, size_t size, size_t* count) {
|
|||
|
||||
bool lovrFileWrite(File* file, const void* data, size_t size, size_t* count) {
|
||||
lovrCheck(file->mode != OPEN_READ, "File was not opened for writing");
|
||||
return fs_write(file->handle.file, data, size, count);
|
||||
return checkfs(fs_write(file->handle.file, data, size, count));
|
||||
}
|
||||
|
||||
bool lovrFileSeek(File* file, uint64_t offset) {
|
||||
|
|
|
@ -18,7 +18,7 @@ typedef enum {
|
|||
|
||||
bool lovrFilesystemInit(void);
|
||||
void lovrFilesystemDestroy(void);
|
||||
void lovrFilesystemSetSource(const char* source);
|
||||
bool lovrFilesystemSetSource(const char* source);
|
||||
const char* lovrFilesystemGetSource(void);
|
||||
bool lovrFilesystemIsFused(void);
|
||||
void lovrFilesystemWatch(void);
|
||||
|
@ -28,8 +28,8 @@ bool lovrFilesystemUnmount(const char* path);
|
|||
const char* lovrFilesystemGetRealDirectory(const char* path);
|
||||
bool lovrFilesystemIsFile(const char* path);
|
||||
bool lovrFilesystemIsDirectory(const char* path);
|
||||
uint64_t lovrFilesystemGetSize(const char* path);
|
||||
uint64_t lovrFilesystemGetLastModified(const char* path);
|
||||
bool lovrFilesystemGetSize(const char* path, uint64_t* size);
|
||||
bool lovrFilesystemGetLastModified(const char* path, uint64_t* modtime);
|
||||
void* lovrFilesystemRead(const char* path, size_t* size);
|
||||
void lovrFilesystemGetDirectoryItems(const char* path, void (*callback)(void* context, const char* path), void* context);
|
||||
const char* lovrFilesystemGetIdentity(void);
|
||||
|
@ -59,7 +59,7 @@ typedef enum {
|
|||
OPEN_APPEND
|
||||
} OpenMode;
|
||||
|
||||
File* lovrFileCreate(const char* path, OpenMode mode, const char** error);
|
||||
File* lovrFileCreate(const char* path, OpenMode mode);
|
||||
void lovrFileDestroy(void* ref);
|
||||
const char* lovrFileGetPath(File* file);
|
||||
OpenMode lovrFileGetMode(File* file);
|
||||
|
|
|
@ -57,11 +57,12 @@ const char* lovrGetError(void) {
|
|||
return error;
|
||||
}
|
||||
|
||||
void lovrSetError(const char* format, ...) {
|
||||
int lovrSetError(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(error, sizeof(error), format, args);
|
||||
va_end(args);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exceptions
|
||||
|
|
|
@ -40,7 +40,7 @@ void lovrRelease(void* ref, void (*destructor)(void*));
|
|||
// Errors
|
||||
|
||||
const char* lovrGetError(void);
|
||||
void lovrSetError(const char* format, ...);
|
||||
int lovrSetError(const char* format, ...);
|
||||
|
||||
#define lovrAssert(c, ...) do { if (!(c)) { lovrSetError(__VA_ARGS__); return 0; } } while (0)
|
||||
#ifdef LOVR_UNCHECKED
|
||||
|
|
Loading…
Reference in a new issue