summaryrefslogtreecommitdiff
path: root/libraries/vfs.h
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/vfs.h')
-rw-r--r--libraries/vfs.h209
1 files changed, 209 insertions, 0 deletions
diff --git a/libraries/vfs.h b/libraries/vfs.h
new file mode 100644
index 0000000..6a243cc
--- /dev/null
+++ b/libraries/vfs.h
@@ -0,0 +1,209 @@
+#ifndef VFS_H
+#define VFS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ char path[256];
+ uint64_t offset;
+ uint64_t size;
+} VfsEntry;
+
+typedef struct {
+ char magic[4];
+ uint32_t num_files;
+} VfsHeader;
+
+typedef struct {
+ FILE* f;
+ uint64_t start;
+ uint64_t size;
+ uint64_t pos;
+ int is_pak;
+} VfsFile;
+
+void vfs_init(const char* pak_path);
+void vfs_shutdown(void);
+
+// Basic API
+void* vfs_read(const char* path, size_t* out_size);
+void vfs_free(void* data);
+
+// Extended API for VFS-like behavior
+VfsFile* vfs_open(const char* path);
+size_t vfs_fread(void* ptr, size_t size, size_t nmemb, VfsFile* file);
+int vfs_fseek(VfsFile* file, int64_t offset, int whence);
+int64_t vfs_ftell(VfsFile* file);
+void vfs_fclose(VfsFile* file);
+
+#ifdef VFS_IMPLEMENTATION
+
+#include <errno.h>
+
+// Note: These must be defined in the implementation file or all.h
+// LOG_INFO, LOG_ERROR, LOG_WARN, log_message
+// If you don't have them, you can define fallbacks here.
+
+static VfsEntry* g_entries = NULL;
+static uint32_t g_num_entries = 0;
+static char g_pak_path[512] = {0};
+static int g_disk_mode = 0;
+
+void vfs_init(const char* pak_path) {
+ const char* debug_env = getenv("DEBUG");
+ if (debug_env && (strcmp(debug_env, "1") == 0 || strcmp(debug_env, "true") == 0)) {
+ g_disk_mode = 1;
+ log_message(stdout, LOG_INFO, "VFS: Operating in Disk Mode (DEBUG enabled)");
+ return;
+ }
+
+ FILE* f = fopen(pak_path, "rb");
+ if (!f) {
+ log_message(stderr, LOG_ERROR, "VFS: Failed to open pak file: %s (Error: %s)", pak_path, strerror(errno));
+ log_message(stderr, LOG_WARN, "VFS: Falling back to Disk Mode");
+ g_disk_mode = 1;
+ return;
+ }
+
+ VfsHeader header;
+ if (fread(&header, sizeof(VfsHeader), 1, f) != 1) {
+ log_message(stderr, LOG_ERROR, "VFS: Failed to read header from %s", pak_path);
+ fclose(f);
+ g_disk_mode = 1;
+ return;
+ }
+
+ if (memcmp(header.magic, "DRP1", 4) != 0) {
+ log_message(stderr, LOG_ERROR, "VFS: Invalid magic in %s", pak_path);
+ fclose(f);
+ g_disk_mode = 1;
+ return;
+ }
+
+ g_num_entries = header.num_files;
+ g_entries = (VfsEntry*)malloc(sizeof(VfsEntry) * g_num_entries);
+ if (fread(g_entries, sizeof(VfsEntry), g_num_entries, f) != g_num_entries) {
+ log_message(stderr, LOG_ERROR, "VFS: Failed to read index table from %s", pak_path);
+ free(g_entries);
+ g_entries = NULL;
+ fclose(f);
+ g_disk_mode = 1;
+ return;
+ }
+
+ fclose(f);
+ strncpy(g_pak_path, pak_path, sizeof(g_pak_path) - 1);
+ log_message(stdout, LOG_INFO, "VFS: Loaded %u files from %s", g_num_entries, pak_path);
+}
+
+void vfs_shutdown(void) {
+ if (g_entries) {
+ free(g_entries);
+ g_entries = NULL;
+ }
+}
+
+VfsFile* vfs_open(const char* path) {
+ if (g_disk_mode) {
+ FILE* f = fopen(path, "rb");
+ if (!f) return NULL;
+ VfsFile* vf = (VfsFile*)malloc(sizeof(VfsFile));
+ vf->f = f;
+ fseek(f, 0, SEEK_END);
+ vf->size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ vf->start = 0;
+ vf->pos = 0;
+ vf->is_pak = 0;
+ return vf;
+ }
+
+ for (uint32_t i = 0; i < g_num_entries; i++) {
+ if (strcmp(g_entries[i].path, path) == 0) {
+ FILE* f = fopen(g_pak_path, "rb");
+ if (!f) return NULL;
+ VfsFile* vf = (VfsFile*)malloc(sizeof(VfsFile));
+ vf->f = f;
+ vf->start = g_entries[i].offset;
+ vf->size = g_entries[i].size;
+ vf->pos = 0;
+ vf->is_pak = 1;
+ fseek(f, (long)vf->start, SEEK_SET);
+ return vf;
+ }
+ }
+
+ log_message(stderr, LOG_WARN, "VFS: File not found: %s", path);
+ return NULL;
+}
+
+size_t vfs_fread(void* ptr, size_t size, size_t nmemb, VfsFile* file) {
+ size_t total_to_read = size * nmemb;
+ if (file->pos + total_to_read > file->size) {
+ total_to_read = (size_t)(file->size - file->pos);
+ }
+
+ if (total_to_read <= 0) return 0;
+
+ size_t read_bytes = fread(ptr, 1, total_to_read, file->f);
+ file->pos += read_bytes;
+ return read_bytes / size;
+}
+
+int vfs_fseek(VfsFile* file, int64_t offset, int whence) {
+ int64_t new_pos;
+ switch (whence) {
+ case SEEK_SET: new_pos = offset; break;
+ case SEEK_CUR: new_pos = (int64_t)file->pos + offset; break;
+ case SEEK_END: new_pos = (int64_t)file->size + offset; break;
+ default: return -1;
+ }
+
+ if (new_pos < 0) new_pos = 0;
+ if (new_pos > (int64_t)file->size) new_pos = (int64_t)file->size;
+
+ file->pos = (uint64_t)new_pos;
+ return fseek(file->f, (long)(file->start + file->pos), SEEK_SET);
+}
+
+int64_t vfs_ftell(VfsFile* file) {
+ return (int64_t)file->pos;
+}
+
+void vfs_fclose(VfsFile* file) {
+ if (file->f) fclose(file->f);
+ free(file);
+}
+
+void* vfs_read(const char* path, size_t* out_size) {
+ VfsFile* f = vfs_open(path);
+ if (!f) return NULL;
+
+ void* data = malloc((size_t)f->size);
+ if (!data) {
+ vfs_fclose(f);
+ return NULL;
+ }
+
+ if (vfs_fread(data, 1, (size_t)f->size, f) != f->size) {
+ free(data);
+ vfs_fclose(f);
+ return NULL;
+ }
+
+ if (out_size) *out_size = (size_t)f->size;
+ vfs_fclose(f);
+ return data;
+}
+
+void vfs_free(void* data) {
+ free(data);
+}
+
+#endif // VFS_IMPLEMENTATION
+
+#endif // VFS_H