#ifndef VFS_H #define VFS_H #include #include #include #include #include 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 // 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