mirror of https://github.com/bjornbytes/lovr.git
Windows;
This commit is contained in:
parent
8795ebb31d
commit
403ed8d3b0
|
@ -145,6 +145,10 @@ void luax_checkvariant(lua_State* L, int index, struct Variant* variant);
|
|||
int luax_pushvariant(lua_State* L, struct Variant* variant);
|
||||
#endif
|
||||
|
||||
#ifdef LOVR_ENABLE_FILESYSTEM
|
||||
void* luax_readfile(const char* filename, size_t* bytesRead);
|
||||
#endif
|
||||
|
||||
#ifdef LOVR_ENABLE_GRAPHICS
|
||||
struct Attachment;
|
||||
struct Texture;
|
||||
|
|
|
@ -50,7 +50,7 @@ static int l_lovrDataNewAudioStream(lua_State* L) {
|
|||
|
||||
static int l_lovrDataNewModelData(lua_State* L) {
|
||||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
ModelData* modelData = lovrModelDataCreate(blob);
|
||||
ModelData* modelData = lovrModelDataCreate(blob, luax_readfile);
|
||||
luax_pushtype(L, ModelData, modelData);
|
||||
lovrRelease(Blob, blob);
|
||||
lovrRelease(ModelData, modelData);
|
||||
|
|
|
@ -13,6 +13,10 @@ const char lovrDirSep = '\\';
|
|||
const char lovrDirSep = '/';
|
||||
#endif
|
||||
|
||||
void* luax_readfile(const char* filename, size_t* bytesRead) {
|
||||
return lovrFilesystemRead(filename, -1, bytesRead);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -23,7 +27,7 @@ Blob* luax_readblob(lua_State* L, int index, const char* debug) {
|
|||
const char* path = luaL_checkstring(L, index);
|
||||
|
||||
size_t size;
|
||||
void* data = lovrFilesystemRead(path, -1, &size);
|
||||
void* data = luax_readfile(path, &size);
|
||||
if (!data) {
|
||||
luaL_error(L, "Could not read %s from '%s'", debug, path);
|
||||
}
|
||||
|
@ -60,7 +64,7 @@ static void pushDirectoryItem(void* context, const char* path) {
|
|||
|
||||
static int luax_loadfile(lua_State* L, const char* path, const char* debug) {
|
||||
size_t size;
|
||||
void* buffer = lovrFilesystemRead(path, -1, &size);
|
||||
void* buffer = luax_readfile(path, &size);
|
||||
int status = luaL_loadbuffer(L, buffer, size, debug);
|
||||
free(buffer);
|
||||
switch (status) {
|
||||
|
@ -259,7 +263,7 @@ static int l_lovrFilesystemLoad(lua_State* L) {
|
|||
static int l_lovrFilesystemMount(lua_State* L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
const char* mountpoint = luaL_optstring(L, 2, NULL);
|
||||
bool append = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
|
||||
bool append = lua_toboolean(L, 3);
|
||||
const char* root = luaL_optstring(L, 4, NULL);
|
||||
lua_pushboolean(L, lovrFilesystemMount(path, mountpoint, append, root));
|
||||
return 1;
|
||||
|
@ -268,7 +272,7 @@ static int l_lovrFilesystemMount(lua_State* L) {
|
|||
static int l_lovrFilesystemNewBlob(lua_State* L) {
|
||||
size_t size;
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
uint8_t* data = lovrFilesystemRead(path, -1, &size);
|
||||
uint8_t* data = luax_readfile(path, &size);
|
||||
lovrAssert(data, "Could not load file '%s'", path);
|
||||
Blob* blob = lovrBlobCreate(data, size, path);
|
||||
luax_pushtype(L, Blob, blob);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "data/modelData.h"
|
||||
#include "data/rasterizer.h"
|
||||
#include "data/textureData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/ref.h"
|
||||
#include <math.h>
|
||||
|
@ -1365,7 +1364,7 @@ static int l_lovrGraphicsNewModel(lua_State* L) {
|
|||
|
||||
if (!modelData) {
|
||||
Blob* blob = luax_readblob(L, 1, "Model");
|
||||
modelData = lovrModelDataCreate(blob);
|
||||
modelData = lovrModelDataCreate(blob, luax_readfile);
|
||||
lovrRelease(Blob, blob);
|
||||
}
|
||||
|
||||
|
@ -1376,29 +1375,25 @@ static int l_lovrGraphicsNewModel(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void luax_readshadersource(lua_State* L, int index) {
|
||||
static const char* luax_checkshadersource(lua_State* L, int index) {
|
||||
if (lua_isnoneornil(L, index)) {
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Blob* blob = luax_totype(L, index, Blob);
|
||||
if (blob) {
|
||||
lua_pushlstring(L, blob->data, blob->size);
|
||||
lua_replace(L, index);
|
||||
return;
|
||||
return blob->data;
|
||||
}
|
||||
|
||||
const char* source = luaL_checkstring(L, index);
|
||||
if (!lovrFilesystemIsFile(source)) {
|
||||
return;
|
||||
size_t length;
|
||||
const char* source = luaL_checklstring(L, index, &length);
|
||||
if (memchr(source, '\n', MIN(1024, length))) {
|
||||
return source;
|
||||
} else {
|
||||
void* contents = luax_readfile(source, &length);
|
||||
lovrAssert(contents, "Could not read shader from file '%s'", source);
|
||||
return contents;
|
||||
}
|
||||
|
||||
size_t bytesRead;
|
||||
char* contents = lovrFilesystemRead(source, -1, &bytesRead);
|
||||
lovrAssert(bytesRead > 0, "Could not read shader from file '%s'", source);
|
||||
lua_pushlstring(L, contents, bytesRead);
|
||||
lua_replace(L, index);
|
||||
free(contents);
|
||||
}
|
||||
|
||||
#define MAX_SHADER_FLAGS 32
|
||||
|
@ -1468,10 +1463,8 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
lovrShaderSetFloats(shader, "lovrLightColor", (float[4]) { 1.f, 1.f, 1.f, 1.f }, 0, 4);
|
||||
}
|
||||
} else {
|
||||
luax_readshadersource(L, 1);
|
||||
luax_readshadersource(L, 2);
|
||||
const char* vertexSource = lua_tostring(L, 1);
|
||||
const char* fragmentSource = lua_tostring(L, 2);
|
||||
const char* vertexSource = luax_checkshadersource(L, 1);
|
||||
const char* fragmentSource = luax_checkshadersource(L, 2);
|
||||
|
||||
if (lua_istable(L, 3)) {
|
||||
lua_getfield(L, 3, "flags");
|
||||
|
@ -1492,8 +1485,7 @@ static int l_lovrGraphicsNewShader(lua_State* L) {
|
|||
}
|
||||
|
||||
static int l_lovrGraphicsNewComputeShader(lua_State* L) {
|
||||
luax_readshadersource(L, 1);
|
||||
const char* source = lua_tostring(L, 1);
|
||||
const char* source = luax_checkshadersource(L, 1);
|
||||
ShaderFlag flags[MAX_SHADER_FLAGS];
|
||||
uint32_t flagCount = 0;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "api.h"
|
||||
#include "event/event.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "thread/thread.h"
|
||||
#include "thread/channel.h"
|
||||
#include "core/ref.h"
|
||||
|
@ -62,7 +61,7 @@ static int l_lovrThreadNewThread(lua_State* L) {
|
|||
memcpy(data, str, length + 1);
|
||||
blob = lovrBlobCreate(data, length, "thread code");
|
||||
} else {
|
||||
void* code = lovrFilesystemRead(str, -1, &length);
|
||||
void* code = luax_readfile(str, &length);
|
||||
lovrAssert(code, "Could not read thread code from file '%s'", str);
|
||||
blob = lovrBlobCreate(code, length, str);
|
||||
}
|
||||
|
|
124
src/core/fs.c
124
src/core/fs.c
|
@ -21,10 +21,19 @@ bool fs_open(const char* path, OpenMode mode, fs_handle* file) {
|
|||
case OPEN_APPEND: access = GENERIC_WRITE; creation = OPEN_ALWAYS; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
file->handle = CreateFileW(wpath, access, share, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
// TODO seek to end of file if appending
|
||||
return file->handle != INVALID_HANDLE_VALUE;
|
||||
if (file->handle == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == OPEN_APPEND && SetFilePointer(file->handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) {
|
||||
CloseHandle(file->handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs_close(fs_handle file) {
|
||||
|
@ -32,19 +41,62 @@ bool fs_close(fs_handle file) {
|
|||
}
|
||||
|
||||
bool fs_read(fs_handle file, void* buffer, size_t* bytes) {
|
||||
return ReadFile(file.handle, buffer, *bytes, bytes, NULL);
|
||||
uint32_t bytes32 = *bytes > UINT32_MAX ? UINT32_MAX : (uint32_t) *bytes;
|
||||
bool success = ReadFile(file.handle, buffer, bytes32, &bytes32, NULL);
|
||||
*bytes = bytes32;
|
||||
return success;
|
||||
}
|
||||
|
||||
bool fs_write(fs_handle file, const void* buffer, size_t* bytes) {
|
||||
return WriteFile(file.handle, buffer, *bytes, bytes, NULL);
|
||||
uint32_t bytes32 = *bytes > UINT32_MAX ? UINT32_MAX : (uint32_t) *bytes;
|
||||
bool success = WriteFile(file.handle, buffer, bytes32, &bytes32, NULL);
|
||||
*bytes = bytes32;
|
||||
return success;
|
||||
}
|
||||
|
||||
void* fs_map(const char* path, size_t* size) {
|
||||
return NULL;
|
||||
WCHAR wpath[FS_PATH_MAX];
|
||||
if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, FS_PATH_MAX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fs_handle file;
|
||||
file.handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file.handle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD hi;
|
||||
DWORD lo = GetFileSize(file.handle, &hi);
|
||||
if (lo == INVALID_FILE_SIZE) {
|
||||
CloseHandle(file.handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (SIZE_MAX > UINT32_MAX) {
|
||||
*size = ((size_t) hi << 32) | lo;
|
||||
} else if (hi > 0) {
|
||||
CloseHandle(file.handle);
|
||||
return NULL;
|
||||
} else {
|
||||
*size = lo;
|
||||
}
|
||||
|
||||
HANDLE mapping = CreateFileMappingA(file.handle, NULL, PAGE_READONLY, hi, lo, NULL);
|
||||
if (mapping == NULL) {
|
||||
CloseHandle(file.handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, *size);
|
||||
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file.handle);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool fs_unmap(void* data, size_t size) {
|
||||
return false;
|
||||
return UnmapViewOfFile(data);
|
||||
}
|
||||
|
||||
bool fs_stat(const char* path, FileInfo* info) {
|
||||
|
@ -59,8 +111,10 @@ bool fs_stat(const char* path, FileInfo* info) {
|
|||
}
|
||||
|
||||
FILETIME lastModified = attributes.ftLastWriteTime;
|
||||
info->type = attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
info->type = (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_DIRECTORY : FILE_REGULAR;
|
||||
info->lastModified = ((uint64_t) lastModified.dwHighDateTime << 32) | lastModified.dwLowDateTime;
|
||||
info->lastModified /= 10000000ULL; // Convert windows 100ns ticks to seconds
|
||||
info->lastModified -= 11644473600ULL; // Convert windows epoch (1601) to POSIX epoch (1970)
|
||||
info->size = ((uint64_t) attributes.nFileSizeHigh << 32) | attributes.nFileSizeLow;
|
||||
return true;
|
||||
}
|
||||
|
@ -82,13 +136,35 @@ bool fs_mkdir(const char* path) {
|
|||
}
|
||||
|
||||
bool fs_list(const char* path, fs_list_cb* callback, void* context) {
|
||||
return false;
|
||||
WCHAR wpath[FS_PATH_MAX];
|
||||
if (!MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, FS_PATH_MAX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WIN32_FIND_DATAW findData;
|
||||
HANDLE handle = FindFirstFileW(wpath, &findData);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char filename[FS_PATH_MAX];
|
||||
do {
|
||||
if (!WideCharToMultiByte(CP_UTF8, 0, findData.cFileName, -1, filename, FS_PATH_MAX, NULL, NULL)) {
|
||||
FindClose(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
callback(context, filename);
|
||||
} while (FindNextFileW(handle, &findData));
|
||||
|
||||
FindClose(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t fs_getHomeDir(char* buffer, size_t size) {
|
||||
PWSTR wpath = NULL;
|
||||
if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &wpath) == S_OK) {
|
||||
size_t bytes = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buffer, size, NULL, NULL);
|
||||
size_t bytes = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buffer, (int) size, NULL, NULL) - 1;
|
||||
CoTaskMemFree(wpath);
|
||||
return bytes;
|
||||
}
|
||||
|
@ -98,7 +174,7 @@ size_t fs_getHomeDir(char* buffer, size_t size) {
|
|||
size_t fs_getDataDir(char* buffer, size_t size) {
|
||||
PWSTR wpath = NULL;
|
||||
if (SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &wpath) == S_OK) {
|
||||
size_t bytes = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buffer, size, NULL, NULL);
|
||||
size_t bytes = WideCharToMultiByte(CP_UTF8, 0, wpath, -1, buffer, (int) size, NULL, NULL) - 1;
|
||||
CoTaskMemFree(wpath);
|
||||
return bytes;
|
||||
}
|
||||
|
@ -107,14 +183,19 @@ size_t fs_getDataDir(char* buffer, size_t size) {
|
|||
|
||||
size_t fs_getWorkDir(char* buffer, size_t size) {
|
||||
WCHAR wpath[FS_PATH_MAX];
|
||||
int length = GetCurrentDirectoryW(size, wpath);
|
||||
int length = GetCurrentDirectoryW((int) size, wpath);
|
||||
if (length) {
|
||||
return WideCharToMultiByte(CP_UTF8, 0, wpath, length, buffer, size, NULL, NULL);
|
||||
return WideCharToMultiByte(CP_UTF8, 0, wpath, length + 1, buffer, (int) size, NULL, NULL) - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t fs_getExecutablePath(char* buffer, size_t size) {
|
||||
WCHAR wpath[FS_PATH_MAX];
|
||||
DWORD length = GetModuleFileNameW(NULL, wpath, FS_PATH_MAX);
|
||||
if (length < FS_PATH_MAX) {
|
||||
return WideCharToMultiByte(CP_UTF8, 0, wpath, length + 1, buffer, (int) size, NULL, NULL) - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -151,27 +232,27 @@ bool fs_open(const char* path, OpenMode mode, fs_handle* file) {
|
|||
}
|
||||
|
||||
bool fs_close(fs_handle file) {
|
||||
return close(file.handle) == 0;
|
||||
return close(file.fd) == 0;
|
||||
}
|
||||
|
||||
bool fs_read(fs_handle file, void* buffer, size_t* bytes) {
|
||||
ssize_t result = read(file.handle, buffer, *bytes);
|
||||
if (result < 0) {
|
||||
ssize_t result = read(file.fd, buffer, *bytes);
|
||||
if (result < 0 || result > UINT32_MAX) {
|
||||
*bytes = 0;
|
||||
return false;
|
||||
} else {
|
||||
*bytes = (size_t) result;
|
||||
*bytes = (uint32_t) result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool fs_write(fs_handle file, const void* buffer, size_t* bytes) {
|
||||
ssize_t result = write(file.handle, buffer, *bytes);
|
||||
if (result < 0) {
|
||||
ssize_t result = write(file.fd, buffer, *bytes);
|
||||
if (result < 0 || result > UINT32_MAX) {
|
||||
*bytes = 0;
|
||||
return false;
|
||||
} else {
|
||||
*bytes = (size_t) result;
|
||||
*bytes = (uint32_t) result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +264,7 @@ void* fs_map(const char* path, size_t* size) {
|
|||
return NULL;
|
||||
}
|
||||
*size = info.size;
|
||||
void* data = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, file.handle, 0);
|
||||
void* data = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, file.fd, 0);
|
||||
fs_close(file);
|
||||
return data;
|
||||
}
|
||||
|
@ -251,6 +332,7 @@ size_t fs_getHomeDir(char* buffer, size_t size) {
|
|||
return copy(buffer, size, home, strlen(home));
|
||||
}
|
||||
|
||||
extern const char* lovrOculusMobileWritablePath; // TODO
|
||||
size_t fs_getDataDir(char* buffer, size_t size) {
|
||||
#if __APPLE__
|
||||
size_t cursor = fs_getHomeDir(buffer, size);
|
||||
|
@ -264,6 +346,8 @@ size_t fs_getDataDir(char* buffer, size_t size) {
|
|||
#elif EMSCRIPTEN
|
||||
const char* path = "/home/web_user";
|
||||
return copy(buffer, size, path, strlen(path));
|
||||
#elif __ANDROID__
|
||||
return copy(buffer, size, lovrOculusMobileWritablePath, strlen(lovrOculusMobileWritablePath));
|
||||
#else
|
||||
const char* xdg = getenv("XDG_DATA_HOME");
|
||||
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#include "zip.h"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
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 uint64_t readu64(const uint8_t* p) { uint64_t x; memcpy(&x, p, sizeof(x)); return x; }
|
||||
|
||||
bool zip_open(zip_state* zip) {
|
||||
const uint8_t* p = zip->data + zip->size - 22;
|
||||
|
@ -47,7 +45,6 @@ bool zip_open(zip_state* zip) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
bool zip_next(zip_state* zip, zip_file* file) {
|
||||
const uint8_t* p = zip->data + zip->cursor;
|
||||
|
||||
|
@ -55,19 +52,8 @@ bool zip_next(zip_state* zip, zip_file* file) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint16_t mtime = readu16(p + 12);
|
||||
uint16_t mdate = readu16(p + 14);
|
||||
struct tm t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.tm_isdst = -1;
|
||||
t.tm_year = ((mdate >> 9) & 127) + 80;
|
||||
t.tm_mon = ((mdate >> 5) & 15) - 1;
|
||||
t.tm_mday = mdate & 31;
|
||||
t.tm_hour = (mtime >> 11) & 31;
|
||||
t.tm_min = (mtime >> 5) & 63;
|
||||
t.tm_sec = (mtime << 1) & 62;
|
||||
file->modtime = mktime(&t);
|
||||
|
||||
file->mtime = readu16(p + 12);
|
||||
file->mdate = readu16(p + 14);
|
||||
file->size = readu32(p + 24);
|
||||
file->length = readu16(p + 28);
|
||||
file->offset = readu32(p + 42) + zip->base;
|
||||
|
@ -96,27 +82,3 @@ void* zip_load(zip_state* zip, size_t offset, size_t* csize, bool* compressed) {
|
|||
uint32_t skip = readu16(p + 26) + readu16(p + 28);
|
||||
return offset + 30 + skip + *csize > zip->size ? NULL : (p + 30 + skip);
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const char *data, long long size) {
|
||||
zip_state zip = {
|
||||
.data = (uint8_t*) data,
|
||||
.size = size
|
||||
};
|
||||
|
||||
if (!zip_open(&zip)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zip_file file;
|
||||
for (uint64_t i = 0; i < zip.count; i++) {
|
||||
if (!zip_next(&zip, &file)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t csize;
|
||||
bool compressed;
|
||||
zip_load(&zip, file.offset, &csize, &compressed);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,9 +24,10 @@ typedef struct {
|
|||
typedef struct {
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint64_t modtime;
|
||||
const char* name;
|
||||
uint16_t length;
|
||||
uint16_t mdate;
|
||||
uint16_t mtime;
|
||||
} zip_file;
|
||||
|
||||
bool zip_open(zip_state* zip);
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#include "core/ref.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
ModelData* lovrModelDataInit(ModelData* model, Blob* source) {
|
||||
if (lovrModelDataInitGltf(model, source)) {
|
||||
ModelData* lovrModelDataInit(ModelData* model, Blob* source, ModelDataIO* io) {
|
||||
if (lovrModelDataInitGltf(model, source, io)) {
|
||||
return model;
|
||||
} else if (lovrModelDataInitObj(model, source)) {
|
||||
} else if (lovrModelDataInitObj(model, source, io)) {
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
|
@ -212,9 +212,11 @@ typedef struct ModelData {
|
|||
map_t nodeMap;
|
||||
} ModelData;
|
||||
|
||||
ModelData* lovrModelDataInit(ModelData* model, struct Blob* blob);
|
||||
typedef void* ModelDataIO(const char* filename, size_t* bytesRead);
|
||||
|
||||
ModelData* lovrModelDataInit(ModelData* model, struct Blob* blob, ModelDataIO* io);
|
||||
#define lovrModelDataCreate(...) lovrModelDataInit(lovrAlloc(ModelData), __VA_ARGS__)
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, struct Blob* blob);
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, struct Blob* blob);
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, struct Blob* blob, ModelDataIO* io);
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, struct Blob* blob, ModelDataIO* io);
|
||||
void lovrModelDataDestroy(void* ref);
|
||||
void lovrModelDataAllocate(ModelData* model);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "data/modelData.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/textureData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "core/hash.h"
|
||||
#include "core/maf.h"
|
||||
#include "core/ref.h"
|
||||
|
@ -148,7 +147,7 @@ static jsmntok_t* resolveTexture(const char* json, jsmntok_t* token, ModelMateri
|
|||
return token;
|
||||
}
|
||||
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
||||
ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source, ModelDataIO* io) {
|
||||
uint8_t* data = source->data;
|
||||
gltfHeader* header = (gltfHeader*) data;
|
||||
bool glb = header->magic == MAGIC_glTF;
|
||||
|
@ -490,7 +489,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
|||
} else {
|
||||
lovrAssert(uri.length < maxPathLength, "Buffer filename is too long");
|
||||
strncat(filename, uri.data, uri.length);
|
||||
*blob = lovrBlobCreate(lovrFilesystemRead(filename, -1, &bytesRead), size, NULL);
|
||||
*blob = lovrBlobCreate(io(filename, &bytesRead), size, NULL);
|
||||
lovrAssert((*blob)->data && bytesRead == size, "Unable to read %s", filename);
|
||||
*root = '\0';
|
||||
}
|
||||
|
@ -671,7 +670,7 @@ ModelData* lovrModelDataInitGltf(ModelData* model, Blob* source) {
|
|||
lovrAssert(uri.length < 5 || strncmp("data:", uri.data, 5), "Base64 images aren't supported yet");
|
||||
lovrAssert(uri.length < maxPathLength, "Image filename is too long");
|
||||
strncat(filename, uri.data, uri.length);
|
||||
void* data = lovrFilesystemRead(filename, -1, &size);
|
||||
void* data = io(filename, &size);
|
||||
lovrAssert(data && size > 0, "Unable to read texture from '%s'", filename);
|
||||
Blob* blob = lovrBlobCreate(data, size, NULL);
|
||||
*texture = lovrTextureDataCreateFromBlob(blob, false);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "data/modelData.h"
|
||||
#include "data/blob.h"
|
||||
#include "data/textureData.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "core/arr.h"
|
||||
#include "core/hash.h"
|
||||
#include "core/maf.h"
|
||||
|
@ -25,9 +24,9 @@ typedef arr_t(objGroup) arr_group_t;
|
|||
|
||||
#define STARTS_WITH(a, b) !strncmp(a, b, strlen(b))
|
||||
|
||||
static void parseMtl(char* path, arr_texturedata_t* textures, arr_material_t* materials, map_t* names, char* base) {
|
||||
static void parseMtl(char* path, ModelDataIO* io, arr_texturedata_t* textures, arr_material_t* materials, map_t* names, char* base) {
|
||||
size_t length = 0;
|
||||
char* data = lovrFilesystemRead(path, -1, &length);
|
||||
char* data = io(path, &length);
|
||||
lovrAssert(data && length > 0, "Unable to read mtl from '%s'", path);
|
||||
char* s = data;
|
||||
|
||||
|
@ -61,7 +60,7 @@ static void parseMtl(char* path, arr_texturedata_t* textures, arr_material_t* ma
|
|||
char path[1024];
|
||||
snprintf(path, sizeof(path), "%s%s", base, filename);
|
||||
size_t size = 0;
|
||||
void* data = lovrFilesystemRead(path, -1, &size);
|
||||
void* data = io(path, &size);
|
||||
lovrAssert(data && size > 0, "Unable to read texture from %s", path);
|
||||
Blob* blob = lovrBlobCreate(data, size, NULL);
|
||||
|
||||
|
@ -87,7 +86,7 @@ static void parseMtl(char* path, arr_texturedata_t* textures, arr_material_t* ma
|
|||
free(data);
|
||||
}
|
||||
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
||||
ModelData* lovrModelDataInitObj(ModelData* model, Blob* source, ModelDataIO* io) {
|
||||
char* data = (char*) source->data;
|
||||
size_t length = source->size;
|
||||
|
||||
|
@ -200,7 +199,7 @@ ModelData* lovrModelDataInitObj(ModelData* model, Blob* source) {
|
|||
lovrAssert(hasName, "Bad OBJ: Expected filename after mtllib");
|
||||
char path[1024];
|
||||
snprintf(path, sizeof(path), "%s%s", base, filename);
|
||||
parseMtl(path, &textures, &materials, &materialMap, base);
|
||||
parseMtl(path, io, &textures, &materials, &materialMap, base);
|
||||
} else if (STARTS_WITH(data, "usemtl ")) {
|
||||
char name[128];
|
||||
uint64_t length = sscanf(data + 7, "%s\n%n", name, &lineLength);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "lib/stb/stb_image.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define FOREACH_ARCHIVE(a) for (Archive* a = state.archives.data; a != state.archives.data + state.archives.length; a++)
|
||||
|
||||
|
@ -30,12 +31,14 @@ typedef struct {
|
|||
uint32_t nextSibling;
|
||||
size_t filename;
|
||||
uint64_t offset;
|
||||
uint16_t mdate;
|
||||
uint16_t mtime;
|
||||
FileInfo info;
|
||||
} zip_node;
|
||||
|
||||
typedef struct Archive {
|
||||
bool (*stat)(struct Archive* archive, const char* path, FileInfo* info);
|
||||
void (*list)(struct Archive* archive, const char* path, void (*callback)(void* context, const char* path), void* context);
|
||||
void (*list)(struct Archive* archive, const char* path, fs_list_cb callback, void* context);
|
||||
bool (*read)(struct Archive* archive, const char* path, size_t bytes, size_t* bytesRead, void** data);
|
||||
bool (*close)(struct Archive* archive);
|
||||
zip_state zip;
|
||||
|
@ -60,16 +63,25 @@ static struct {
|
|||
} state;
|
||||
|
||||
static bool valid(const char* path) {
|
||||
char c;
|
||||
if (path[0] == '.' && (path[1] == '\0' || path[1] == '.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
c = *path++;
|
||||
if (c == ':' || c == '\\' || (c == '.' && *path == '.')) {
|
||||
if (
|
||||
*path == ':' ||
|
||||
*path == '\\' ||
|
||||
(*path == '/' && path[1] == '.' &&
|
||||
(path[2] == '.' ? (path[3] == '/' || path[3] == '\0') : (path[2] == '/' || path[2] == '\0')))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} while (c != '\0');
|
||||
} while (*path++ != '\0');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
memcpy(buffer + length1 + 1, p2, length2);
|
||||
|
@ -142,6 +154,12 @@ static bool dir_init(Archive* archive, const char* path, const char* mountpoint,
|
|||
static bool zip_init(Archive* archive, const char* path, const char* mountpoint, const char* root);
|
||||
|
||||
bool lovrFilesystemMount(const char* path, const char* mountpoint, bool append, const char* root) {
|
||||
FOREACH_ARCHIVE(archive) {
|
||||
if (!strcmp(strpool_resolve(&archive->strings, archive->path), path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Archive archive;
|
||||
arr_init(&archive.strings);
|
||||
|
||||
|
@ -472,8 +490,25 @@ static zip_node* zip_lookup(Archive* archive, const char* path) {
|
|||
}
|
||||
|
||||
static bool zip_stat(Archive* archive, const char* path, FileInfo* info) {
|
||||
const zip_node* node = zip_lookup(archive, path);
|
||||
zip_node* node = zip_lookup(archive, path);
|
||||
if (!node) return false;
|
||||
|
||||
// zip stores timestamps in dos time, conversion is slow so we do it only on request
|
||||
if (node->info.lastModified == ~0ull) {
|
||||
uint16_t mdate = node->mdate;
|
||||
uint16_t mtime = node->mtime;
|
||||
struct tm t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.tm_isdst = -1;
|
||||
t.tm_year = ((mdate >> 9) & 127) + 80;
|
||||
t.tm_mon = ((mdate >> 5) & 15) - 1;
|
||||
t.tm_mday = mdate & 31;
|
||||
t.tm_hour = (mtime >> 11) & 31;
|
||||
t.tm_min = (mtime >> 5) & 63;
|
||||
t.tm_sec = (mtime << 1) & 62;
|
||||
node->info.lastModified = mktime(&t);
|
||||
}
|
||||
|
||||
*info = node->info;
|
||||
return true;
|
||||
}
|
||||
|
@ -513,15 +548,15 @@ static bool zip_read(Archive* archive, const char* path, size_t bytes, size_t* b
|
|||
return true;
|
||||
}
|
||||
|
||||
*bytesRead = (bytes == (size_t) -1 || bytes > dstSize) ? dstSize : bytes;
|
||||
*bytesRead = (bytes == (size_t) -1 || bytes > dstSize) ? (uint32_t) dstSize : bytes;
|
||||
|
||||
if (compressed) {
|
||||
if (stbi_zlib_decode_noheader_buffer(*dst, dstSize, src, srcSize) < 0) {
|
||||
if (stbi_zlib_decode_noheader_buffer(*dst, (int) dstSize, src, (int) srcSize) < 0) {
|
||||
free(*dst);
|
||||
*dst = NULL;
|
||||
}
|
||||
} else {
|
||||
memcpy(*dst, src, bytes);
|
||||
memcpy(*dst, src, *bytesRead);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -536,6 +571,7 @@ static bool zip_close(Archive* archive) {
|
|||
static bool zip_init(Archive* archive, const char* filename, const char* mountpoint, const char* root) {
|
||||
char path[LOVR_PATH_MAX];
|
||||
memset(&archive->lookup, 0, sizeof(archive->lookup));
|
||||
arr_init(&archive->nodes);
|
||||
|
||||
// mmap the zip file, try to parse it, and figure out how many files there are
|
||||
archive->zip.data = fs_map(filename, &archive->zip.size);
|
||||
|
@ -564,7 +600,6 @@ static bool zip_init(Archive* archive, const char* filename, const char* mountpo
|
|||
while (root && root[rootLength - 1] == '/') rootLength--;
|
||||
|
||||
// Allocate
|
||||
arr_init(&archive->nodes);
|
||||
map_init(&archive->lookup, archive->zip.count);
|
||||
arr_reserve(&archive->nodes, archive->zip.count);
|
||||
|
||||
|
@ -581,8 +616,10 @@ static bool zip_init(Archive* archive, const char* filename, const char* mountpo
|
|||
.nextSibling = ~0u,
|
||||
.filename = (size_t) -1,
|
||||
.offset = info.offset,
|
||||
.mdate = info.mdate,
|
||||
.mtime = info.mtime,
|
||||
.info.size = info.size,
|
||||
.info.lastModified = info.modtime,
|
||||
.info.lastModified = ~0ull,
|
||||
.info.type = FILE_REGULAR
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue