Remove some legacy sm64ex code

This commit is contained in:
Agent X 2024-05-11 16:30:25 -04:00
parent 940a05a2d1
commit c91b390d80
6 changed files with 6 additions and 709 deletions

View file

@ -17,7 +17,6 @@
#include "../platform.h"
#include "fs.h"
char fs_gamedir[SYS_MAX_PATH] = "";
char fs_writepath[SYS_MAX_PATH] = "";
struct fs_dir_s {
@ -28,11 +27,9 @@ struct fs_dir_s {
};
extern fs_packtype_t fs_packtype_dir;
extern fs_packtype_t fs_packtype_zip;
static fs_packtype_t *fs_packers[] = {
&fs_packtype_dir,
&fs_packtype_zip,
&fs_packtype_dir
};
static fs_dir_t *fs_searchpaths = NULL;
@ -44,45 +41,7 @@ static inline fs_dir_t *fs_find_dir(const char *realpath) {
return NULL;
}
static int mount_cmp(const void *p1, const void *p2) {
const char *s1 = sys_file_name(*(const char **)p1);
const char *s2 = sys_file_name(*(const char **)p2);
// check if one or both of these are basepacks
const int plen = strlen(FS_BASEPACK_PREFIX);
const bool is_base1 = !strncmp(s1, FS_BASEPACK_PREFIX, plen);
const bool is_base2 = !strncmp(s2, FS_BASEPACK_PREFIX, plen);
// if both are basepacks, compare the postfixes only
if (is_base1 && is_base2) return strcmp(s1 + plen, s2 + plen);
// if only one is a basepack, it goes first
if (is_base1) return -1;
if (is_base2) return 1;
// otherwise strcmp order
return strcmp(s1, s2);
}
static void scan_path_dir(const char *ropath, const char *dir) {
char dirpath[SYS_MAX_PATH];
snprintf(dirpath, sizeof(dirpath), "%s/%s", ropath, dir);
if (!fs_sys_dir_exists(dirpath)) return;
// since filename order in readdir() isn't guaranteed, collect paths and sort them in strcmp() order
// (but with basepacks first)
fs_pathlist_t plist = fs_sys_enumerate(dirpath, false);
if (plist.paths) {
qsort(plist.paths, plist.numpaths, sizeof(char *), mount_cmp);
for (int32_t i = 0; i < plist.numpaths; ++i)
fs_mount(plist.paths[i]);
fs_pathlist_free(&plist);
}
// mount the directory itself
fs_mount(dirpath);
}
bool fs_init(const char **rodirs, const char *gamedir, const char *writepath) {
bool fs_init(const char *writepath) {
char buf[SYS_MAX_PATH];
// expand and remember the write path
@ -92,26 +51,6 @@ bool fs_init(const char **rodirs, const char *gamedir, const char *writepath) {
printf("fs: writepath set to `%s`\n", fs_writepath);
#endif
// remember the game directory name
strncpy(fs_gamedir, gamedir, sizeof(fs_gamedir));
fs_gamedir[sizeof(fs_gamedir)-1] = 0;
#ifdef DEVELOPMENT
printf("fs: gamedir set to `%s`\n", fs_gamedir);
#endif
// first, scan all possible paths and mount all basedirs in them
for (const char **p = rodirs; p && *p; ++p)
scan_path_dir(fs_convert_path(buf, sizeof(buf), *p), FS_BASEDIR);
scan_path_dir(fs_writepath, FS_BASEDIR);
// then mount all the gamedirs in them, if the game dir isn't the same
if (sys_strcasecmp(FS_BASEDIR, fs_gamedir)) {
for (const char **p = rodirs; p && *p; ++p)
scan_path_dir(fs_convert_path(buf, sizeof(buf), *p), fs_gamedir);
scan_path_dir(fs_writepath, fs_gamedir);
}
// as a special case, mount writepath itself
fs_mount(fs_writepath);
return true;
@ -164,20 +103,6 @@ bool fs_mount(const char *realpath) {
return true;
}
bool fs_unmount(const char *realpath) {
fs_dir_t *dir = fs_find_dir(realpath);
if (dir) {
dir->packer->unmount(dir->pack);
free((void *)dir->realpath);
if (dir->prev) dir->prev->next = dir->next;
if (dir->next) dir->next->prev = dir->prev;
if (dir == fs_searchpaths) fs_searchpaths = dir->next;
free(dir);
return true;
}
return false;
}
fs_walk_result_t fs_walk(const char *base, walk_fn_t walkfn, void *user, const bool recur) {
bool found = false;
for (fs_dir_t *dir = fs_searchpaths; dir; dir = dir->next) {
@ -190,22 +115,6 @@ fs_walk_result_t fs_walk(const char *base, walk_fn_t walkfn, void *user, const b
return found ? FS_WALK_SUCCESS : FS_WALK_NOTFOUND;
}
bool fs_is_file(const char *fname) {
for (fs_dir_t *dir = fs_searchpaths; dir; dir = dir->next) {
if (dir->packer->is_file(dir->pack, fname))
return true;
}
return false;
}
bool fs_is_dir(const char *fname) {
for (fs_dir_t *dir = fs_searchpaths; dir; dir = dir->next) {
if (dir->packer->is_dir(dir->pack, fname))
return true;
}
return false;
}
fs_file_t *fs_open(const char *vpath) {
for (fs_dir_t *dir = fs_searchpaths; dir; dir = dir->next) {
fs_file_t *f = dir->packer->open(dir->pack, vpath);
@ -227,16 +136,6 @@ int64_t fs_read(fs_file_t *file, void *buf, const uint64_t size) {
return file->parent->packer->read(file->parent->pack, file, buf, size);
}
bool fs_seek(fs_file_t *file, const int64_t ofs) {
if (!file) return -1;
return file->parent->packer->seek(file->parent->pack, file, ofs);
}
int64_t fs_tell(fs_file_t *file) {
if (!file) return -1;
return file->parent->packer->tell(file->parent->pack, file);
}
int64_t fs_size(fs_file_t *file) {
if (!file) return -1;
return file->parent->packer->size(file->parent->pack, file);
@ -254,31 +153,6 @@ struct matchdata_s {
size_t dst_len;
};
static bool match_walk(void *user, const char *path) {
struct matchdata_s *data = (struct matchdata_s *)user;
if (!strncmp(path, data->prefix, data->prefix_len)) {
// found our lad, copy path to destination and terminate
strncpy(data->dst, path, data->dst_len);
data->dst[data->dst_len - 1] = 0;
return false;
}
return true;
}
const char *fs_match(char *outname, const size_t outlen, const char *prefix) {
struct matchdata_s data = {
.prefix = prefix,
.prefix_len = strlen(prefix),
.dst = outname,
.dst_len = outlen,
};
if (fs_walk("", match_walk, &data, true) == FS_WALK_INTERRUPTED)
return outname;
return NULL;
}
static bool enumerate_walk(void *user, const char *path) {
fs_pathlist_t *data = (fs_pathlist_t *)user;
@ -440,18 +314,6 @@ bool fs_sys_walk(const char *base, walk_fn_t walk, void *user, const bool recur)
#endif
}
fs_pathlist_t fs_sys_enumerate(const char *base, const bool recur) {
char **paths = malloc(sizeof(char *) * 32);
fs_pathlist_t pathlist = { paths, 0, 32 };
if (!paths) return pathlist;
if (!fs_sys_walk(base, enumerate_walk, &pathlist, recur))
fs_pathlist_free(&pathlist);
return pathlist;
}
bool fs_sys_mkdir(const char *name) {
#ifdef _WIN32
return _mkdir(name) == 0;

View file

@ -8,21 +8,8 @@
#include "../platform.h"
// FS_BASEDIR is usually defined in the build script
#ifndef FS_BASEDIR
# define FS_BASEDIR "res"
#endif
#ifndef FS_BASEPACK_PREFIX
# define FS_BASEPACK_PREFIX "base"
#endif
#define FS_TEXTUREDIR "gfx"
#define FS_SOUNDDIR "sound"
#define SAVE_FILENAME "sm64_save_file.bin"
extern char fs_gamedir[];
extern char fs_writepath[];
// receives the full path
@ -81,16 +68,12 @@ typedef struct {
// takes the supplied NULL-terminated list of read-only directories and mounts all the packs in them,
// then mounts the directories themselves, then mounts all the packs in `gamedir`, then mounts `gamedir` itself,
// then does the same with `userdir`
// initializes the `fs_gamedir` and `fs_userdir` variables
bool fs_init(const char **rodirs, const char *gamedir, const char *userdir);
// initializes the `fs_userdir` variable
bool fs_init(const char *userdir);
// mounts the pack at physical path `realpath` to the root of the filesystem
// packs mounted later take priority over packs mounted earlier
bool fs_mount(const char *realpath);
// removes the pack at physical path from the virtual filesystem
bool fs_unmount(const char *realpath);
/* generalized filesystem functions that call matching packtype functions for each pack in the searchpath */
// FIXME: this can walk in unorthodox patterns, since it goes through mountpoints linearly
@ -101,25 +84,16 @@ fs_pathlist_t fs_enumerate(const char *base, const bool recur);
// call this on a list returned by fs_enumerate() to free it
void fs_pathlist_free(fs_pathlist_t *pathlist);
bool fs_is_file(const char *fname);
bool fs_is_dir(const char *fname);
fs_file_t *fs_open(const char *vpath);
void fs_close(fs_file_t *file);
int64_t fs_read(fs_file_t *file, void *buf, const uint64_t size);
const char *fs_readline(fs_file_t *file, char *dst, const uint64_t size);
bool fs_seek(fs_file_t *file, const int64_t ofs);
int64_t fs_tell(fs_file_t *file);
int64_t fs_size(fs_file_t *file);
bool fs_eof(fs_file_t *file);
void *fs_load_file(const char *vpath, uint64_t *outsize);
const char *fs_readline(fs_file_t *file, char *dst, uint64_t size);
// tries to find the first file with the filename that starts with `prefix`
// puts full filename into `outname` and returns it or returns NULL if nothing matches
const char *fs_match(char *outname, const size_t outlen, const char *prefix);
// takes a virtual path and prepends the write path to it
const char *fs_get_write_path(const char *vpath);
@ -129,7 +103,6 @@ const char *fs_convert_path(char *buf, const size_t bufsiz, const char *path);
/* these operate on the real filesystem and are used by fs_packtype_dir */
bool fs_sys_walk(const char *base, walk_fn_t walk, void *user, const bool recur);
fs_pathlist_t fs_sys_enumerate(const char *base, const bool recur);
bool fs_sys_file_exists(const char *name);
bool fs_sys_dir_exists(const char *name);
bool fs_sys_mkdir(const char *name); // creates with 0777 by default

View file

@ -1,490 +0,0 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <tinfl.h>
#include "macros.h"
#include "../platform.h"
#include "fs.h"
#include "dirtree.h"
#define ZIP_BUFSIZE 16384
#define ZIP_EOCD_BUFSIZE 65578
#define ZIP_LFH_SIG 0x04034b50
#define ZIP_CDH_SIG 0x02014b50
#define ZIP_EOCD_SIG 0x06054b50
typedef struct {
fs_dirtree_t tree; // this should always be first, so this could be used as a dirtree root
const char *realpath; // physical path to the zip file
FILE *zipf; // open zip file handle, if any
} zip_pack_t;
typedef struct {
fs_dirtree_entry_t tree; // this should always be first, so this could be used as a dirtree entry
uint64_t ofs; // offset to compressed data in zip
uint16_t bits; // general purpose zip flags
uint16_t comptype; // compression method
uint32_t crc; // CRC-32
uint64_t comp_size; // size of compressed data in zip
uint64_t uncomp_size; // size of decompressed data
uint16_t attr_int; // internal attributes
uint32_t attr_ext; // external attributes
bool ofs_fixed; // if true, `ofs` points to the file data, otherwise to LFH
} zip_entry_t;
typedef struct {
zip_entry_t *entry; // the dirtree entry of this file
uint32_t comp_pos; // read position in compressed data
uint32_t uncomp_pos; // read position in uncompressed data
uint8_t *buffer; // decompression buffer (if compressed)
z_stream zstream; // tinfl zlib stream
FILE *fstream; // duplicate of zipf of the parent zip file
} zip_file_t;
static int64_t zip_find_eocd(FILE *f, int64_t *outlen) {
// the EOCD is somewhere in the last 65557 bytes of the file
// get the total file size
fseek(f, 0, SEEK_END);
const int64_t fsize = ftell(f);
if (fsize <= 16) return -1; // probably not a zip
const int64_t rx = (fsize < ZIP_EOCD_BUFSIZE ? fsize : ZIP_EOCD_BUFSIZE);
uint8_t *buf = malloc(rx);
if (!buf) return -1;
// read that entire chunk and search for EOCD backwards from the end
fseek(f, fsize - rx, SEEK_SET);
if (fread(buf, rx, 1, f)) {
for (int64_t i = rx - 8; i >= 0; --i) {
if ((buf[i + 0] == 0x50) && (buf[i + 1] == 0x4B) &&
(buf[i + 2] == 0x05) && (buf[i + 3] == 0x06)) {
// gotem
free(buf);
if (outlen) *outlen = fsize;
return fsize - rx + i;
}
}
}
free(buf);
return -1;
}
static bool zip_parse_eocd(FILE *f, uint64_t *cdir_ofs, uint64_t *data_ofs, uint64_t *count) {
int64_t fsize = 0;
// EOCD record struct
struct eocd_s {
uint32_t sig;
uint16_t this_disk;
uint16_t cdir_disk;
uint16_t disk_entry_count;
uint16_t total_entry_count;
uint32_t cdir_size;
uint32_t cdir_ofs;
uint16_t comment_len;
// zip comment follows
} __attribute__((__packed__));
struct eocd_s eocd;
// find the EOCD and seek to it
int64_t pos = zip_find_eocd(f, &fsize);
if (pos < 0) return false;
fseek(f, pos, SEEK_SET);
// read it
if (!fread(&eocd, sizeof(eocd), 1, f)) return false;
// double check the sig
if (LE_TO_HOST32(eocd.sig) != ZIP_EOCD_SIG) return false;
// disks should all be 0
if (eocd.this_disk || eocd.cdir_disk) return false;
// total entry count should be the same as disk entry count
if (eocd.disk_entry_count != eocd.total_entry_count) return false;
*count = LE_TO_HOST16(eocd.total_entry_count);
*cdir_ofs = LE_TO_HOST32(eocd.cdir_ofs);
eocd.cdir_size = LE_TO_HOST32(eocd.cdir_size);
// end of central dir can't be before central dir
if ((uint64_t)pos < *cdir_ofs + eocd.cdir_size) return false;
*data_ofs = (uint64_t)(pos - (*cdir_ofs + eocd.cdir_size));
*cdir_ofs += *data_ofs;
// make sure end of comment matches end of file
eocd.comment_len = LE_TO_HOST16(eocd.comment_len);
return ((pos + 22 + eocd.comment_len) == fsize);
}
static bool zip_fixup_offset(zip_file_t *zipfile) {
// LFH record struct
struct lfh_s {
uint32_t sig;
uint16_t version_required;
uint16_t bits;
uint16_t comptype;
uint16_t mod_time;
uint16_t mod_date;
uint32_t crc;
uint32_t comp_size;
uint32_t uncomp_size;
uint16_t fname_len;
uint16_t extra_len;
// file name, extra field and data follow
} __attribute__((__packed__));
struct lfh_s lfh;
zip_entry_t *ent = zipfile->entry;
fseek(zipfile->fstream, ent->ofs, SEEK_SET);
if (!fread(&lfh, sizeof(lfh), 1, zipfile->fstream)) return false;
// we only need these two
lfh.fname_len = LE_TO_HOST16(lfh.fname_len);
lfh.extra_len = LE_TO_HOST16(lfh.extra_len);
// ofs will now point to actual data
ent->ofs += sizeof(lfh) + lfh.fname_len + lfh.extra_len;
ent->ofs_fixed = true; // only need to do this once
return true;
}
static zip_entry_t *zip_load_entry(FILE *f, fs_dirtree_t *tree, const uint64_t data_ofs) {
// CDH record struct
struct cdh_s {
uint32_t sig;
uint16_t version_used;
uint16_t version_required;
uint16_t bits;
uint16_t comptype;
uint16_t mod_time;
uint16_t mod_date;
uint32_t crc;
uint32_t comp_size;
uint32_t uncomp_size;
uint16_t fname_len;
uint16_t extra_len;
uint16_t comment_len;
uint16_t start_disk;
uint16_t attr_int;
uint32_t attr_ext;
uint32_t lfh_ofs;
// file name, extra field and comment follow
} __attribute__((__packed__));
struct cdh_s cdh;
zip_entry_t zipent;
memset(&zipent, 0, sizeof(zipent));
if (!fread(&cdh, sizeof(cdh), 1, f)) return NULL;
// check cdir entry header signature
if (LE_TO_HOST32(cdh.sig) != ZIP_CDH_SIG) return NULL;
// byteswap and copy some important fields
zipent.bits = LE_TO_HOST16(cdh.bits);
zipent.comptype = LE_TO_HOST16(cdh.comptype);
zipent.crc = LE_TO_HOST32(cdh.crc);
zipent.comp_size = LE_TO_HOST32(cdh.comp_size);
zipent.uncomp_size = LE_TO_HOST32(cdh.uncomp_size);
zipent.ofs = LE_TO_HOST32(cdh.lfh_ofs);
zipent.attr_int = LE_TO_HOST16(cdh.attr_int);
zipent.attr_ext = LE_TO_HOST32(cdh.attr_ext);
cdh.fname_len = LE_TO_HOST16(cdh.fname_len);
cdh.comment_len = LE_TO_HOST16(cdh.comment_len);
cdh.extra_len = LE_TO_HOST16(cdh.extra_len);
// read the name
char *name = calloc(1, cdh.fname_len + 1);
if (!name) return NULL;
if (!fread(name, cdh.fname_len, 1, f)) { free(name); return NULL; }
// this is a directory if the name ends in a path separator
bool is_dir = false;
if (name[cdh.fname_len - 1] == '/') {
is_dir = true;
name[cdh.fname_len - 1] = 0;
}
name[cdh.fname_len] = 0;
// add to directory tree
zip_entry_t *retent = (zip_entry_t *)fs_dirtree_add(tree, name, is_dir);
free(name);
if (!retent) return NULL;
// copy the data we read into the new entry
zipent.tree = retent->tree;
memcpy(retent, &zipent, sizeof(zipent));
// this points to the LFH now; will be fixed up on file open
// while the CDH includes an "extra field length" field, it's usually different
retent->ofs += data_ofs;
// skip to the next CDH
fseek(f, cdh.extra_len + cdh.comment_len, SEEK_CUR);
return retent;
}
static inline bool zip_load_entries(FILE *f, fs_dirtree_t *tree, const uint64_t cdir_ofs, const uint64_t data_ofs, const uint64_t count) {
fseek(f, cdir_ofs, SEEK_SET);
for (uint64_t i = 0; i < count; ++i) {
if (!zip_load_entry(f, tree, data_ofs))
return false;
}
return true;
}
static inline bool is_zip(FILE *f) {
uint32_t sig = 0;
if (fread(&sig, sizeof(sig), 1, f)) {
// the first LFH might be at the start of the zip
if (LE_TO_HOST32(sig) == ZIP_LFH_SIG)
return true;
// no signature, might still be a zip because fuck you
// the only way now is to try and find the end of central directory
return zip_find_eocd(f, NULL) >= 0;
}
return false;
}
static void *pack_zip_mount(const char *realpath) {
uint64_t cdir_ofs, data_ofs, count;
zip_pack_t *pack = NULL;
FILE *f = NULL;
f = fopen(realpath, "rb");
if (!f) goto _fail;
if (!is_zip(f)) goto _fail;
pack = calloc(1, sizeof(zip_pack_t));
if (!pack) goto _fail;
if (!zip_parse_eocd(f, &cdir_ofs, &data_ofs, &count))
goto _fail;
if (!fs_dirtree_init(&pack->tree, sizeof(zip_entry_t)))
goto _fail;
if (!zip_load_entries(f, &pack->tree, cdir_ofs, data_ofs, count))
goto _fail;
pack->realpath = sys_strdup(realpath);
pack->zipf = f;
return pack;
_fail:
if (f) fclose(f);
if (pack) free(pack);
return NULL;
}
static void pack_zip_unmount(void *pack) {
zip_pack_t *zip = (zip_pack_t *)pack;
fs_dirtree_free(&zip->tree);
if (zip->realpath) free((void *)zip->realpath);
if (zip->zipf) fclose(zip->zipf);
free(zip);
}
static bool pack_zip_is_file(void *pack, const char *fname) {
zip_entry_t *ent = (zip_entry_t *)fs_dirtree_find((fs_dirtree_t *)pack, fname);
return ent && !ent->tree.is_dir;
}
static bool pack_zip_is_dir(void *pack, const char *fname) {
zip_entry_t *ent = (zip_entry_t *)fs_dirtree_find((fs_dirtree_t *)pack, fname);
return ent && ent->tree.is_dir;
}
static inline void pack_zip_close_zipfile(zip_file_t *zipfile) {
if (zipfile->buffer) {
inflateEnd(&zipfile->zstream);
free(zipfile->buffer);
}
if (zipfile->fstream) fclose(zipfile->fstream);
free(zipfile);
}
static fs_file_t *pack_zip_open(void *pack, const char *vpath) {
fs_file_t *fsfile = NULL;
zip_file_t *zipfile = NULL;
zip_pack_t *zip = (zip_pack_t *)pack;
zip_entry_t *ent = (zip_entry_t *)fs_dirtree_find((fs_dirtree_t *)zip, vpath);
if (!ent || ent->tree.is_dir) goto _fail; // we're expecting a fucking file here
zipfile = calloc(1, sizeof(zip_file_t));
if (!zipfile) goto _fail;
zipfile->entry = ent;
// obtain an additional file descriptor
// fdopen(dup(fileno())) is not very portable and might not create separate state
zipfile->fstream = fopen(zip->realpath, "rb");
if (!zipfile->fstream) goto _fail;
// make ent->ofs point to the actual file data if it doesn't already
if (!ent->ofs_fixed)
if (!zip_fixup_offset(zipfile))
goto _fail; // this shouldn't generally happen but oh well
// if there's compression, assume it's zlib
if (ent->comptype != 0) {
zipfile->buffer = malloc(ZIP_BUFSIZE);
if (!zipfile->buffer)
goto _fail;
if (inflateInit2(&zipfile->zstream, -MAX_WBITS) != Z_OK)
goto _fail;
}
fsfile = malloc(sizeof(fs_file_t));
if (!fsfile) goto _fail;
fsfile->handle = zipfile;
fsfile->parent = NULL;
// point to the start of the file data
fseek(zipfile->fstream, ent->ofs, SEEK_SET);
return fsfile;
_fail:
if (zipfile) pack_zip_close_zipfile(zipfile);
if (fsfile) free(fsfile);
return NULL;
}
static void pack_zip_close(UNUSED void *pack, fs_file_t *file) {
if (!file) return;
zip_file_t *zipfile = (zip_file_t *)file->handle;
if (zipfile) pack_zip_close_zipfile(zipfile);
free(file);
}
static int64_t pack_zip_read(UNUSED void *pack, fs_file_t *file, void *buf, const uint64_t size) {
zip_file_t *zipfile = (zip_file_t *)file->handle;
zip_entry_t *ent = zipfile->entry;
int64_t avail = ent->uncomp_size - zipfile->uncomp_pos;
int64_t max_read = ((int64_t)size > avail) ? avail : (int64_t)size;
int64_t rx = 0;
int err = 0;
if (max_read == 0) return 0;
if (ent->comptype == 0) {
// no compression, just read
rx = fread(buf, 1, size, zipfile->fstream);
} else {
zipfile->zstream.next_out = buf;
zipfile->zstream.avail_out = (unsigned int)max_read;
while (rx < max_read) {
const uint32_t before = (uint32_t)zipfile->zstream.total_out;
// check if we ran out of compressed bytes and read more if we did
if (zipfile->zstream.avail_in == 0) {
int32_t comp_rx = ent->comp_size - zipfile->comp_pos;
if (comp_rx > 0) {
if (comp_rx > ZIP_BUFSIZE) comp_rx = ZIP_BUFSIZE;
comp_rx = fread(zipfile->buffer, 1, comp_rx, zipfile->fstream);
if (comp_rx == 0) break;
zipfile->comp_pos += (uint32_t)comp_rx;
zipfile->zstream.next_in = zipfile->buffer;
zipfile->zstream.avail_in = (unsigned int)comp_rx;
}
}
// inflate
err = inflate(&zipfile->zstream, Z_SYNC_FLUSH);
rx += zipfile->zstream.total_out - before;
if (err != Z_OK) break;
}
}
zipfile->uncomp_pos += rx;
return rx;
}
static bool pack_zip_seek(UNUSED void *pack, fs_file_t *file, const int64_t ofs) {
zip_file_t *zipfile = (zip_file_t *)file->handle;
zip_entry_t *ent = zipfile->entry;
uint8_t buf[512];
if (ofs > (int64_t)ent->uncomp_size) return false;
if (ent->comptype == 0) {
if (fseek(zipfile->fstream, ofs + ent->ofs, SEEK_SET) == 0)
zipfile->uncomp_pos = ofs;
} else {
// if seeking backwards, gotta redecode the stream from the start until that point
// so we make a copy of the zstream and clear it with a new one
if (ofs < zipfile->uncomp_pos) {
z_stream zstream;
memset(&zstream, 0, sizeof(zstream));
if (inflateInit2(&zstream, -MAX_WBITS) != Z_OK)
return false;
// reset the underlying file handle back to the start
if (fseek(zipfile->fstream, ent->ofs, SEEK_SET) != 0) {
if (zstream.zfree) {
zstream.zfree(zstream.opaque, zstream.state);
}
return false;
}
// free and replace the old one
inflateEnd(&zipfile->zstream);
memcpy(&zipfile->zstream, &zstream, sizeof(zstream));
zipfile->uncomp_pos = zipfile->comp_pos = 0;
}
// continue decoding the stream until we hit the new offset
while (zipfile->uncomp_pos != ofs) {
uint32_t max_read = (uint32_t)(ofs - zipfile->uncomp_pos);
if (max_read > sizeof(buf)) max_read = sizeof(buf);
if (pack_zip_read(pack, file, buf, max_read) != max_read)
return false;
}
}
return true;
}
static int64_t pack_zip_tell(UNUSED void *pack, fs_file_t *file) {
return ((zip_file_t *)file->handle)->uncomp_pos;
}
static int64_t pack_zip_size(UNUSED void *pack, fs_file_t *file) {
zip_file_t *zipfile = (zip_file_t *)file->handle;
return zipfile->entry->uncomp_size;
}
static bool pack_zip_eof(UNUSED void *pack, fs_file_t *file) {
zip_file_t *zipfile = (zip_file_t *)file->handle;
return zipfile->uncomp_pos >= zipfile->entry->uncomp_size;
}
fs_packtype_t fs_packtype_zip = {
"zip",
pack_zip_mount,
pack_zip_unmount,
fs_dirtree_walk,
pack_zip_is_file,
pack_zip_is_dir,
pack_zip_open,
pack_zip_read,
pack_zip_seek,
pack_zip_tell,
pack_zip_size,
pack_zip_eof,
pack_zip_close,
};

View file

@ -369,7 +369,7 @@ int main(int argc, char *argv[]) {
#endif
const char *userpath = gCLIOpts.savePath[0] ? gCLIOpts.savePath : sys_user_path();
fs_init(sys_ropaths, FS_BASEDIR, userpath);
fs_init(userpath);
configfile_load();
// Create the window straight away

View file

@ -9,20 +9,6 @@
#include "fs/fs.h"
#include "configfile.h"
/* NULL terminated list of platform specific read-only data paths */
/* priority is top first */
const char *sys_ropaths[] = {
".", // working directory
"!", // executable directory
#if defined(__linux__) || defined(__unix__)
// some common UNIX directories for read only stuff
"/usr/local/share/sm64pc",
"/usr/share/sm64pc",
"/opt/sm64pc",
#endif
NULL,
};
/* these are not available on some platforms, so might as well */
char *sys_strlwr(char *src) {
@ -95,35 +81,6 @@ void sys_fatal(const char *fmt, ...) {
// we can just ask SDL for most of this shit if we have it
#include <SDL2/SDL.h>
// TEMPORARY: check the old save folder and copy contents to the new path
// this will be removed after a while
static inline bool copy_userdata(const char *userdir) {
char oldpath[SYS_MAX_PATH] = { 0 };
char path[SYS_MAX_PATH] = { 0 };
// check if a save already exists in the new folder
snprintf(path, sizeof(path), "%s/" SAVE_FILENAME, userdir);
if (fs_sys_file_exists(path)) return false;
// check if a save exists in the old folder ('pc' instead of 'ex')
strncpy(oldpath, path, sizeof(oldpath));
const unsigned int len = strlen(userdir);
oldpath[len - 2] = 'p'; oldpath[len - 1] = 'c';
if (!fs_sys_file_exists(oldpath)) return false;
printf("old save detected at '%s', copying to '%s'\n", oldpath, path);
bool ret = fs_sys_copy_file(oldpath, path);
// also try to copy the config
path[len] = oldpath[len] = 0;
strncat(path, "/" CONFIGFILE_DEFAULT, SYS_MAX_PATH - 1);
strncat(oldpath, "/" CONFIGFILE_DEFAULT, SYS_MAX_PATH - 1);
fs_sys_copy_file(oldpath, path);
return ret;
}
const char *sys_user_path(void) {
static char path[SYS_MAX_PATH] = { 0 };
@ -141,8 +98,6 @@ const char *sys_user_path(void) {
if (!fs_sys_dir_exists(path) && !fs_sys_mkdir(path))
path[0] = 0; // somehow failed, we got no user path
else
copy_userdata(path); // TEMPORARY: try to copy old saves, if any
}
return path;

View file

@ -5,13 +5,10 @@
#include <stdlib.h>
#include <string.h>
/* Platform-specific functions and whatnot */
/* platform-specific functions and whatnot */
#define SYS_MAX_PATH 4096 // FIXME: define this on different platforms
// NULL terminated list of platform specific read-only data paths
extern const char *sys_ropaths[];
// crossplatform impls of misc stuff
char *sys_strdup(const char *src);
char *sys_strlwr(char *src);