diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-04-28 07:45:45 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-04-28 07:45:45 +0200 |
| commit | 0ed91795a2db720e688fd2daefd22f7e9c754c2f (patch) | |
| tree | 1856de605b3888132ad6917cbeb3ecf677bbda6d /libraries/vfs.h | |
| download | stalag-0ed91795a2db720e688fd2daefd22f7e9c754c2f.tar.gz | |
Engage!
Diffstat (limited to 'libraries/vfs.h')
| -rw-r--r-- | libraries/vfs.h | 209 |
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 |
