diff --git a/src/pc/fs/fs.c b/src/pc/fs/fs.c index 7e250694..6aeace2e 100644 --- a/src/pc/fs/fs.c +++ b/src/pc/fs/fs.c @@ -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; diff --git a/src/pc/fs/fs.h b/src/pc/fs/fs.h index 25d176df..6a50c1be 100644 --- a/src/pc/fs/fs.h +++ b/src/pc/fs/fs.h @@ -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 diff --git a/src/pc/fs/fs_packtype_zip.c b/src/pc/fs/fs_packtype_zip.c deleted file mode 100644 index c86cffc3..00000000 --- a/src/pc/fs/fs_packtype_zip.c +++ /dev/null @@ -1,490 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#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, -}; diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 82e8f64a..84e2e092 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -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 diff --git a/src/pc/platform.c b/src/pc/platform.c index 5a2b5675..9906793a 100644 --- a/src/pc/platform.c +++ b/src/pc/platform.c @@ -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 -// 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; diff --git a/src/pc/platform.h b/src/pc/platform.h index 2a1dc342..47694f40 100644 --- a/src/pc/platform.h +++ b/src/pc/platform.h @@ -5,13 +5,10 @@ #include #include -/* 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);