diff --git a/file_io.cpp b/file_io.cpp index 0f8c61b..d70320e 100644 --- a/file_io.cpp +++ b/file_io.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "osd.h" #include "fpga_io.h" #include "menu.h" @@ -22,6 +23,7 @@ #include "user_io.h" #include "cfg.h" #include "input.h" +#include "miniz_zip.h" #include "scheduler.h" typedef std::vector DirentVector; @@ -34,8 +36,181 @@ int iFirstEntry = 0; static char full_path[1200]; +struct fileZipArchive +{ + mz_zip_archive archive; + int index; + mz_zip_reader_extract_iter_state* iter; + __off64_t offset; +}; + +static bool FileIsZipped(const std::string& path, std::string* zip_path, std::string* file_path) +{ + const std::string zipext(".zip"); + auto it = std::search(path.begin(), path.end(), + zipext.begin(), zipext.end(), + [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }); + + if (it != path.end()) + { + if (zip_path) + { + *zip_path = std::string(path.begin(), it + zipext.length()); + } + if (file_path) + { + if ((it + zipext.length()) < path.end()) + { + *file_path = std::string(it + zipext.length() + 1, path.end()); + } + else + { + *file_path = {}; + } + } + return true; + } + return false; +} + +static int get_stmode(const char *path) +{ + sprintf(full_path, "%s/%s", getRootDir(), path); + struct stat64 st; + return (stat64(path, &st) < 0) ? 0 : st.st_mode; +} + +static bool isPathDirectory(const std::string& path) +{ + std::string full_path{path}; + if (full_path[0] != '/') + { + full_path = std::string(getRootDir()) + "/" + path; + } + + std::string zip_path, file_path; + if (FileIsZipped(full_path, &zip_path, &file_path)) + { + mz_zip_archive z{}; + if (!mz_zip_reader_init_file(&z, zip_path.c_str(), 0)) + { + printf("isPathDirectory(mz_zip_reader_init_file) Zip:%s, error:%s\n", zip_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&z))); + return false; + } + + if (file_path.empty()) + { + mz_zip_reader_end(&z); + return true; + } + + // Folder names always end with a slash in the zip + // file central directory. + file_path += "/"; + const int file_index = mz_zip_reader_locate_file(&z, file_path.c_str(), NULL, 0); + if (file_index < 0) + { + printf("isPathDirectory(mz_zip_reader_locate_file) Zip:%s, file:%s, error: %s\n", + zip_path.c_str(), file_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&z))); + mz_zip_reader_end(&z); + return false; + } + + if (mz_zip_reader_is_file_a_directory(&z, file_index)) + { + mz_zip_reader_end(&z); + return true; + } + mz_zip_reader_end(&z); + } + else + { + int stmode = get_stmode(path.c_str()); + if (!stmode) + { + printf("isPathDirectory(stat) path:%s, error:%s.\n", path.c_str(), strerror(errno)); + return false; + } + + if (stmode & S_IFDIR) return true; + } + + return false; +} + +static bool isPathRegularFile(const std::string& path) +{ + std::string full_path{path}; + if (full_path[0] != '/') + { + full_path = std::string(getRootDir()) + "/" + path; + } + + std::string zip_path, file_path; + if (FileIsZipped(full_path, &zip_path, &file_path)) + { + mz_zip_archive z{}; + if (!mz_zip_reader_init_file(&z, zip_path.c_str(), 0)) + { + printf("isPathDirectory(mz_zip_reader_init_file) Zip:%s, error:%s\n", zip_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&z))); + return false; + } + + if (file_path.empty()) + { + mz_zip_reader_end(&z); + return false; + } + + const int file_index = mz_zip_reader_locate_file(&z, file_path.c_str(), NULL, 0); + if (file_index < 0) + { + printf("isPathDirectory(mz_zip_reader_locate_file) Zip:%s, file:%s, error: %s\n", + zip_path.c_str(), file_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&z))); + mz_zip_reader_end(&z); + return false; + } + + if (!mz_zip_reader_is_file_a_directory(&z, file_index) && mz_zip_reader_is_file_supported(&z, file_index)) + { + mz_zip_reader_end(&z); + return true; + } + mz_zip_reader_end(&z); + } + else + { + int stmode = get_stmode(path.c_str()); + if (!stmode) + { + printf("isPathDirectory(stat) path:%s, error:%s.\n", path.c_str(), strerror(errno)); + return false; + } + + if (stmode & S_IFREG) return true; + } + + return false; +} + void FileClose(fileTYPE *file) { + if (file->zip) + { + if (file->zip->iter) + { + mz_zip_reader_extract_iter_free(file->zip->iter); + } + mz_zip_reader_end(&file->zip->archive); + + delete file->zip; + file->zip = nullptr; + } + if (file->filp) { //printf("closing %p\n", file->filp); @@ -68,47 +243,101 @@ int FileOpenEx(fileTYPE *file, const char *name, int mode, char mute) file->mode = 0; file->type = 0; - char *p = strrchr(full_path, '/'); - strcpy(file->name, (mode == -1) ? full_path : p+1); - - int fd = (mode == -1) ? shm_open("/vtrd", O_CREAT | O_RDWR | O_TRUNC, 0777) : open(full_path, mode, 0777); - if (fd <= 0) + std::string zip_path, file_path; + if (FileIsZipped(full_path, &zip_path, &file_path)) { - if(!mute) printf("FileOpenEx(open) File:%s, error: %s.\n", full_path, strerror(errno)); - return 0; - } - - const char *fmode = mode & O_RDWR ? "w+" : "r"; - file->filp = fdopen(fd, fmode); - if (!file->filp) - { - if(!mute) printf("FileOpenEx(fdopen) File:%s, error: %s.\n", full_path, strerror(errno)); - close(fd); - return 0; - } - - if (mode == -1) - { - file->type = 1; - file->size = 0; - file->offset = 0; - file->mode = O_CREAT | O_RDWR | O_TRUNC; - } - else - { - struct stat64 st; - int ret = fstat64(fd, &st); - if (ret < 0) + if (mode & O_RDWR || mode & O_WRONLY) { - if (!mute) printf("FileOpenEx(fstat) File:%s, error: %d.\n", full_path, ret); + if(!mute) printf("FileOpenEx(mode) Zip:%s, writing to zipped files is not supported.\n", + full_path); + return 0; + } + + file->zip = new fileZipArchive{}; + if (!mz_zip_reader_init_file(&file->zip->archive, zip_path.c_str(), 0)) + { + if(!mute) printf("FileOpenEx(mz_zip_reader_init_file) Zip:%s, error:%s\n", zip_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + return 0; + } + + file->zip->index = mz_zip_reader_locate_file(&file->zip->archive, file_path.c_str(), NULL, 0); + if (file->zip->index < 0) + { + if(!mute) printf("FileOpenEx(mz_zip_reader_locate_file) Zip:%s, file:%s, error: %s\n", + zip_path.c_str(), file_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); FileClose(file); return 0; } - file->size = st.st_size; + mz_zip_archive_file_stat s; + if (!mz_zip_reader_file_stat(&file->zip->archive, file->zip->index, &s)) + { + if(!mute) printf("FileOpenEx(mz_zip_reader_file_stat) Zip:%s, file:%s, error:%s\n", + zip_path.c_str(), file_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + FileClose(file); + return 0; + } + file->size = s.m_uncomp_size; + + file->zip->iter = mz_zip_reader_extract_iter_new(&file->zip->archive, file->zip->index, 0); + if (!file->zip->iter) + { + if(!mute) printf("FileOpenEx(mz_zip_reader_extract_iter_new) Zip:%s, file:%s, error:%s\n", + zip_path.c_str(), file_path.c_str(), + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + FileClose(file); + return 0; + } + file->zip->offset = 0; file->offset = 0; file->mode = mode; } + else + { + char *p = strrchr(full_path, '/'); + strcpy(file->name, (mode == -1) ? full_path : p+1); + + int fd = (mode == -1) ? shm_open("/vtrd", O_CREAT | O_RDWR | O_TRUNC, 0777) : open(full_path, mode, 0777); + if (fd <= 0) + { + if(!mute) printf("FileOpenEx(open) File:%s, error: %s.\n", full_path, strerror(errno)); + return 0; + } + const char *fmode = mode & O_RDWR ? "w+" : "r"; + file->filp = fdopen(fd, fmode); + if (!file->filp) + { + if(!mute) printf("FileOpenEx(fdopen) File:%s, error: %s.\n", full_path, strerror(errno)); + close(fd); + return 0; + } + + if (mode == -1) + { + file->type = 1; + file->size = 0; + file->offset = 0; + file->mode = O_CREAT | O_RDWR | O_TRUNC; + } + else + { + struct stat64 st; + int ret = fstat64(fileno(file->filp), &st); + if (ret < 0) + { + if (!mute) printf("FileOpenEx(fstat) File:%s, error: %d.\n", full_path, ret); + FileClose(file); + return 0; + } + + file->size = st.st_size; + file->offset = 0; + file->mode = mode; + } + } //printf("opened %s, size %lu\n", full_path, file->size); return 1; @@ -116,11 +345,17 @@ int FileOpenEx(fileTYPE *file, const char *name, int mode, char mute) __off64_t FileGetSize(fileTYPE *file) { - if (!file->filp) return 0; - - struct stat64 st; - int ret = fstat64(fileno(file->filp), &st); - return (ret < 0) ? 0 : st.st_size; + if (file->filp) + { + struct stat64 st; + int ret = fstat64(fileno(file->filp), &st); + return (ret < 0) ? 0 : st.st_size; + } + else if (file->zip) + { + return file->size; + } + return 0; } int FileOpen(fileTYPE *file, const char *name, char mute) @@ -130,28 +365,88 @@ int FileOpen(fileTYPE *file, const char *name, char mute) int FileNextSector(fileTYPE *file) { - __off64_t newoff = lseek64(fileno(file->filp), file->offset + 512, SEEK_SET); - if (newoff != file->offset + 512) + if (file->filp) { - //printf("Fail to seek to next sector. File: %s.\n", file->name); - lseek64(fileno(file->filp), file->offset, SEEK_SET); - return 0; - } + __off64_t newoff = lseek64(fileno(file->filp), file->offset + 512, SEEK_SET); + if (newoff != file->offset + 512) + { + //printf("Fail to seek to next sector. File: %s.\n", file->name); + lseek64(fileno(file->filp), file->offset, SEEK_SET); + return 0; + } - file->offset = newoff; - return 1; + file->offset = newoff; + return 1; + } + else if (file->zip) + { + if (!FileSeek(file, file->offset + 512, SEEK_SET)) + { + FileSeek(file, file->offset, SEEK_SET); + return 0; + } + return 1; + } + return 0; } int FileSeek(fileTYPE *file, __off64_t offset, int origin) { - __off64_t newoff = lseek64(fileno(file->filp), offset, origin); - if(newoff<0) + if (file->filp) + { + offset = lseek64(fileno(file->filp), offset, origin); + if(offset<0) + { + printf("Fail to seek the file.\n"); + return 0; + } + } + else if (file->zip) + { + if (origin == SEEK_CUR) + { + offset = file->zip->offset + offset; + } + else if (origin == SEEK_END) + { + offset = file->size - offset; + } + + if (offset < file->zip->offset) + { + mz_zip_reader_extract_iter_state *iter = mz_zip_reader_extract_iter_new(&file->zip->archive, file->zip->index, 0); + if (!iter) + { + printf("FileSeek(mz_zip_reader_extract_iter_new) Failed to rewind iterator, error:%s\n", + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + return 0; + } + + mz_zip_reader_extract_iter_free(file->zip->iter); + file->zip->iter = iter; + file->zip->offset = 0; + } + + char buf[512]; + while (file->zip->offset < offset) + { + const size_t want_len = std::min((__off64_t)sizeof(buf), offset - file->zip->offset); + const size_t read_len = mz_zip_reader_extract_iter_read(file->zip->iter, buf, want_len); + file->zip->offset += read_len; + if (read_len < want_len) + { + printf("FileSeek(mz_zip_reader_extract_iter_read) Failed to advance iterator, error:%s\n", + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + return 0; + } + } + } + else { - printf("Fail to seek the file.\n"); return 0; } - file->offset = newoff; + file->offset = offset; return 1; } @@ -182,10 +477,30 @@ int FileReadEx(fileTYPE *file, void *pBuffer, int nSize) { for (int i = 0; i < nSize; i++) { - int ret = fread(tmpbuff, 512, 1, file->filp); - if (ret < 0) + if (file->filp) { - printf("FileRead error(%d).\n", ret); + int ret = fread(tmpbuff, 512, 1, file->filp); + if (ret < 0) + { + printf("FileRead error(%d).\n", ret); + return 0; + } + i += ret; + } + else if (file->zip) + { + size_t ret = mz_zip_reader_extract_iter_read(file->zip->iter, tmpbuff, 512); + if (!ret) + { + printf("FileReadEx(mz_zip_reader_extract_iter_read) Failed to read, error:%s\n", + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + return 0; + } + file->zip->offset += ret; + } + else + { + printf("FileRead error(unknown file type).\n"); return 0; } @@ -196,10 +511,34 @@ int FileReadEx(fileTYPE *file, void *pBuffer, int nSize) } else { - int ret = fread(pBuffer, nSize, 512, file->filp); - if (ret < 0) + if (file->filp) { - printf("FileRead error(%d).\n", ret); + int ret = fread(pBuffer, nSize, 512, file->filp); + if (ret < 0) + { + printf("FileRead error(%d).\n", ret); + return 0; + } + } + else if (file->zip) + { + char *p = (char*)pBuffer; + for (int i = 0; i < nSize; i++) + { + size_t ret = mz_zip_reader_extract_iter_read(file->zip->iter, p, 512); + if (!ret) + { + printf("FileReadEx(mz_zip_reader_extract_iter_read) Failed to read, error:%s\n", + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + return 0; + } + p += ret; + file->zip->offset += ret; + } + } + else + { + printf("FileRead error(unknown file type).\n"); return 0; } } @@ -216,10 +555,23 @@ int FileWrite(fileTYPE *file, void *pBuffer) return 0; } - int ret = fwrite(pBuffer, 512, 1, file->filp); - if (ret < 0) + if (file->filp) { - printf("FileWrite error(%d).\n", ret); + int ret = fwrite(pBuffer, 512, 1, file->filp); + if (ret < 0) + { + printf("FileWrite error(%d).\n", ret); + return 0; + } + } + else if (file->zip) + { + printf("FileWrite error(not supported for zip).\n"); + return 0; + } + else + { + printf("FileWrite error(unknown file type).\n"); return 0; } @@ -229,11 +581,32 @@ int FileWrite(fileTYPE *file, void *pBuffer) // Read with offset advancing int FileReadAdv(fileTYPE *file, void *pBuffer, int length) { - ssize_t ret = fread(pBuffer, length, 1, file->filp); - if (ret < 0) + ssize_t ret = 0; + + if (file->filp) { - printf("FileReadAdv error(%d).\n", ret); - return 0; + ret = fread(pBuffer, length, 1, file->filp); + if (ret < 0) + { + printf("FileReadAdv error(%d).\n", ret); + return 0; + } + } + else if (file->zip) + { + ret = mz_zip_reader_extract_iter_read(file->zip->iter, pBuffer, length); + if (!ret) + { + printf("FileReadEx(mz_zip_reader_extract_iter_read) Failed to read, error:%s\n", + mz_zip_get_error_string(mz_zip_get_last_error(&file->zip->archive))); + return 0; + } + file->zip->offset += ret; + } + else + { + printf("FileReadAdv error(unknown file type).\n"); + return -1; } file->offset += ret; @@ -248,10 +621,25 @@ int FileReadSec(fileTYPE *file, void *pBuffer) // Write with offset advancing int FileWriteAdv(fileTYPE *file, void *pBuffer, int length) { - int ret = fwrite(pBuffer, length, 1, file->filp); - if (ret < 0) + int ret; + + if (file->filp) { - printf("FileWriteAdv error(%d).\n", ret); + ret = fwrite(pBuffer, length, 1, file->filp); + if (ret < 0) + { + printf("FileWriteAdv error(%d).\n", ret); + return 0; + } + } + else if (file->zip) + { + printf("FileWriteAdv error(not supported for zip).\n"); + return 0; + } + else + { + printf("FileWriteAdv error(unknown file type).\n"); return 0; } @@ -267,6 +655,12 @@ int FileWriteSec(fileTYPE *file, void *pBuffer) int FileSave(const char *name, void *pBuffer, int size) { sprintf(full_path, "%s/%s", getRootDir(), name); + if (!FileCanWrite(name)) + { + printf("FileSave(FileCanWrite) File:%s, not writable.\n", full_path); + return 0; + } + int fd = open(full_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRWXU | S_IRWXG | S_IRWXO); if (fd < 0) { @@ -341,6 +735,11 @@ int FileCanWrite(const char *name) { sprintf(full_path, "%s/%s", getRootDir(), name); + if (FileIsZipped(full_path, nullptr, nullptr)) + { + return 0; + } + struct stat64 st; int ret = stat64(full_path, &st); if (ret < 0) @@ -353,6 +752,36 @@ int FileCanWrite(const char *name) return ((st.st_mode & S_IWUSR) != 0); } +void FileGenerateSavePath(const char *name, const char* extension, char* out_name, int length) +{ + const char *d = strrchr(name, '.'); + if (d) + { + const int l = std::min(d - name, length); + strncpy(out_name, name, l); + out_name[l] = '\0'; + } + else + { + strncpy(out_name, name, length); + } + + char *z = strcasestr(out_name, ".zip"); + if (z) + { + // Remove '.' from '.zip' so file logic won't think + // the file has been compressed. + *z = '-'; + for (char *p = z; (p = strchr(p, '/')); ) + { + *p = '-'; + } + } + + strncat(out_name, ".", length); + strncat(out_name, extension, length); +} + uint32_t getFileType(const char *name) { sprintf(full_path, "%s/%s", getRootDir(), name); @@ -565,24 +994,9 @@ struct DirentComp size_t iterations = 0; }; -static int get_stmode(const char *path) -{ - sprintf(full_path, "%s/%s", getRootDir(), path); - struct stat64 st; - return (stat64(full_path, &st) < 0) ? 0 : st.st_mode; -} - void AdjustDirectory(char *path) { - int stmode = get_stmode(path); - if (!stmode) - { - printf("AdjustDirectory(stat) path:%s, error.\n", path); - path[0] = 0; - return; - } - - if (stmode & S_IFDIR) return; + if (isPathDirectory(path)) return; char *p = strrchr(path, '/'); if (p) @@ -595,6 +1009,20 @@ void AdjustDirectory(char *path) } } +static bool IsInSameFolder(const char *folder, const char *path) +{ + if (strcasestr(path, folder) == path) + { + const char *subpath = path + strlen(folder) + 1; + if (*subpath != '\0') + { + const char *slash = strchr(subpath, '/'); + return !slash || *(slash + 1) == '\0'; + } + } + return false; +} + int ScanDirectory(char* path, int mode, const char *extension, int options, const char *prefix) { static char file_name[1024]; @@ -607,6 +1035,12 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons ext += 3; } + const char* is_zipped = strcasestr(path, ".zip"); + if (is_zipped && strcasestr(is_zipped + 4, ".zip")) + { + printf("Nested zip-files are not supported: %s\n", path); + return 0; + } int extlen = strlen(extension); //printf("scan dir\n"); @@ -614,8 +1048,7 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons if (mode == SCANF_INIT) { file_name[0] = 0; - int stmode = get_stmode(path); - if (!(stmode & S_IFDIR)) + if (!isPathDirectory(path)) { char *p = strrchr(path, '/'); if (p) @@ -629,37 +1062,80 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons path[0] = 0; } - if (!(stmode & S_IFREG)) file_name[0] = 0; + if (!isPathRegularFile(path)) file_name[0] = 0; } - if (!(get_stmode(path) & S_IFDIR)) + if (!isPathDirectory(path)) { path[0] = 0; file_name[0] = 0; } sprintf(full_path, "%s/%s", getRootDir(), path); - printf("Start to scan dir: %s\n", full_path); + printf("Start to scan %sdir: %s\n", is_zipped ? "zipped " : "", full_path); + + std::string zip_path, file_path_in_zip; + FileIsZipped(full_path, &zip_path, &file_path_in_zip); iFirstEntry = 0; iSelectedEntry = 0; DirItem.clear(); - DIR *d = opendir(full_path); - if (!d) + DIR *d = nullptr; + mz_zip_archive *z = nullptr; + if (is_zipped) { - printf("Couldn't open dir: %s\n", full_path); - return 0; + mz_zip_archive _z = { 0 }; + if (!mz_zip_reader_init_file(&_z, zip_path.c_str(), 0)) + { + printf("Couldn't open zip file %s: %s\n", full_path, mz_zip_get_error_string(mz_zip_get_last_error(z))); + return 0; + } + z = new mz_zip_archive(_z); + } + else + { + d = opendir(full_path); + if (!d) + { + printf("Couldn't open dir: %s\n", full_path); + return 0; + } } - struct dirent *de; - for (size_t i = 0; (de = readdir(d)); i++) + struct dirent *de = nullptr; + for (size_t i = 0; (d && (de = readdir(d))) + || (z && i < mz_zip_reader_get_num_files(z)); i++) { if (0 < i && i % YieldIterations == 0) { scheduler_yield(); } + struct dirent _de = { 0 }; + if (z) { + mz_zip_reader_get_filename(z, i, &_de.d_name[0], sizeof(_de.d_name)); + if (!IsInSameFolder(file_path_in_zip.c_str(), _de.d_name)) + { + continue; + } + // Remove leading folders. + const char* subpath = _de.d_name + file_path_in_zip.length(); + if (*subpath == '/') + { + subpath++; + } + strcpy(_de.d_name, subpath); + + _de.d_type = mz_zip_reader_is_file_a_directory(z, i) ? DT_DIR : DT_REG; + if (_de.d_type == DT_DIR) + { + // Remove trailing slash. + _de.d_name[strlen(_de.d_name) - 1] = '\0'; + } + de = &_de; + } + if (de->d_type == DT_DIR) { if (!strcmp(de->d_name, ".")) continue; @@ -688,6 +1164,12 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons int len = strlen(de->d_name); const char *ext = extension; int found = (has_trd && x2trd_ext_supp(de->d_name)); + if (!found && !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".zip")) + { + // Fake that zip-file is a directory. + de->d_type = DT_DIR; + found = 1; + } if (!found && is_minimig() && !memcmp(extension, "HDF", 3)) { found = !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".iso"); @@ -732,7 +1214,22 @@ int ScanDirectory(char* path, int mode, const char *extension, int options, cons } DirItem.push_back(*de); } - closedir(d); + if (z) + { + // Since zip files aren't actually folders the entry to + // exit the zip file must be added manually. + dirent up; + up.d_type = DT_DIR; + strcpy(up.d_name, ".."); + DirItem.push_back(up); + + mz_zip_reader_end(z); + delete z; + } + if (d) + { + closedir(d); + } printf("Got %d dir entries\n", flist_nDirEntries()); if (!flist_nDirEntries()) return 0; diff --git a/file_io.h b/file_io.h index e34a43b..580684f 100644 --- a/file_io.h +++ b/file_io.h @@ -7,15 +7,18 @@ #include #include "spi.h" +struct fileZipArchive; + typedef struct { - FILE *filp; - int mode; - int type; - __off64_t size; - __off64_t offset; - char path[1024]; - char name[261]; + FILE *filp; + int mode; + int type; + fileZipArchive *zip; + __off64_t size; + __off64_t offset; + char path[1024]; + char name[261]; } fileTYPE; int flist_nDirEntries(); @@ -65,6 +68,7 @@ int FileWriteAdv(fileTYPE *file, void *pBuffer, int length); int FileWriteSec(fileTYPE *file, void *pBuffer); int FileCanWrite(const char *name); +void FileGenerateSavePath(const char *name, const char* extension, char* out_name, int length); int FileSave(const char *name, void *pBuffer, int size); int FileLoad(const char *name, void *pBuffer, int size); // supply pBuffer = 0 to get the file size without loading diff --git a/user_io.cpp b/user_io.cpp index 27877b2..630a80a 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -1299,10 +1299,7 @@ int user_io_file_tx(const char* name, unsigned char index, char opensave, char m if (opensave) { - strcpy((char*)buf, name); - char *p = strrchr((char*)buf, '.'); - if (!p) p = (char*)buf + strlen(name); - strcpy(p, ".sav"); + FileGenerateSavePath(name, "sav", (char*)buf, sizeof(buf)); user_io_file_mount((char*)buf, 0, 1); }