sm64pc/src/pc/fs/fs_packtype_dir.c

118 lines
3.2 KiB
C

#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include "macros.h"
#include "../platform.h"
#include "fs.h"
static void *pack_dir_mount(const char *realpath) {
if (!fs_sys_dir_exists(realpath))
return NULL;
// the pack is actually just the real folder path
void *pack = (void *)sys_strdup(realpath);
return pack;
}
static void pack_dir_unmount(void *pack) {
free(pack);
}
struct walkdata_s {
size_t baselen;
walk_fn_t userwalk;
void *userdata;
};
// wrap the actual user walk function to return virtual paths instead of real paths
static bool packdir_walkfn(void *userdata, const char *path) {
struct walkdata_s *walk = (struct walkdata_s *)userdata;
return walk->userwalk(walk->userdata, path + walk->baselen);
}
static fs_walk_result_t pack_dir_walk(void *pack, const char *base, walk_fn_t walkfn, void *user, const bool recur) {
char path[SYS_MAX_PATH];
snprintf(path, SYS_MAX_PATH, "%s/%s", (const char *)pack, base);
if (!fs_sys_dir_exists(path))
return FS_WALK_NOTFOUND;
struct walkdata_s walkdata = { strlen((const char *)pack) + 1, walkfn, user };
return fs_sys_walk(path, packdir_walkfn, &walkdata, recur);
}
static bool pack_dir_is_file(void *pack, const char *fname) {
char path[SYS_MAX_PATH];
snprintf(path, sizeof(path), "%s/%s", (const char *)pack, fname);
return fs_sys_dir_exists(path);
}
static bool pack_dir_is_dir(void *pack, const char *fname) {
char path[SYS_MAX_PATH];
snprintf(path, sizeof(path), "%s/%s", (const char *)pack, fname);
return fs_sys_file_exists(path);
}
static fs_file_t *pack_dir_open(void *pack, const char *vpath) {
char path[SYS_MAX_PATH];
snprintf(path, sizeof(path), "%s/%s", (const char *)pack, vpath);
FILE *f = fopen(path, "rb");
if (!f) return NULL;
fs_file_t *fsfile = malloc(sizeof(fs_file_t));
if (!fsfile) { fclose(f); return NULL; }
fsfile->parent = NULL;
fsfile->handle = f;
return fsfile;
}
static void pack_dir_close(UNUSED void *pack, fs_file_t *file) {
fclose((FILE *)file->handle);
free(file);
}
static int64_t pack_dir_read(UNUSED void *pack, fs_file_t *file, void *buf, const uint64_t size) {
return fread(buf, 1, size, (FILE *)file->handle);
}
static bool pack_dir_seek(UNUSED void *pack, fs_file_t *file, const int64_t ofs) {
return fseek((FILE *)file->handle, ofs, SEEK_SET) == 0;
}
static int64_t pack_dir_tell(UNUSED void *pack, fs_file_t *file) {
return ftell((FILE *)file->handle);
}
static int64_t pack_dir_size(UNUSED void *pack, fs_file_t *file) {
int64_t oldofs = ftell((FILE *)file->handle);
fseek((FILE *)file->handle, 0, SEEK_END);
int64_t size = ftell((FILE *)file->handle);
fseek((FILE *)file->handle, oldofs, SEEK_SET);
return size;
}
static bool pack_dir_eof(UNUSED void *pack, fs_file_t *file) {
return feof((FILE *)file->handle);
}
fs_packtype_t fs_packtype_dir = {
"",
pack_dir_mount,
pack_dir_unmount,
pack_dir_walk,
pack_dir_is_file,
pack_dir_is_dir,
pack_dir_open,
pack_dir_read,
pack_dir_seek,
pack_dir_tell,
pack_dir_size,
pack_dir_eof,
pack_dir_close,
};