#pragma once struct FSCVirtualFile; #define FSC_TYPE_INVALID (0) #define FSC_TYPE_FILE (1) #define FSC_TYPE_DIRECTORY (2) #define FSC_QUERY_SIZE (1) // file size, 0 for directories #define FSC_QUERY_WRITEABLE (2) // non-zero if file is writeable, else 0 enum class FSC_ACCESS_FLAG : uint8 { NONE = 0, // file permissions READ_PERMISSION = (1<<0), WRITE_PERMISSION = (1<<1), // file open mode (incompatible with OPEN_DIR flag) FILE_ALLOW_CREATE = (1 << 2), // create file if it does not exist FILE_ALWAYS_CREATE = (1 << 3), // overwrite any existing file // which types can be opened // invalid operation if neither is set OPEN_DIR = (1 << 4), OPEN_FILE = (1 << 5), // Writing seeks to the end of the file if set IS_APPEND = (1 << 6) }; DEFINE_ENUM_FLAG_OPERATORS(FSC_ACCESS_FLAG); #define FSC_STATUS_UNDEFINED (-1) #define FSC_STATUS_OK (0) #define FSC_STATUS_INVALID_PATH (1) #define FSC_STATUS_FILE_NOT_FOUND (2) #define FSC_STATUS_ALREADY_EXISTS (3) // note: Unlike the native Wii U filesystem, FSC does not provide separate error codes for NOT_A_FILE and NOT_A_DIRECTORY // to determine them manually, open with both modes (file and dir) and check the type #define FSC_MAX_DIR_NAME_LENGTH (256) #define FSC_MAX_DEVICE_PATH_LENGTH ((std::max)(260,FSA_PATH_SIZE_MAX)) // max length for FSC device paths (should be at least equal or greater than supported by host filesystem) struct FSCDirEntry { char path[FSC_MAX_DIR_NAME_LENGTH]; // stats bool isDirectory; bool isFile; uint32 fileSize; std::string_view GetPath() { size_t len = strnlen(path, FSC_MAX_DIR_NAME_LENGTH); return std::basic_string_view(path, len); } }; class fscDeviceC { public: virtual FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) { cemu_assert_unimplemented(); return nullptr; } virtual bool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus) { cemu_assert_unimplemented(); return false; } virtual bool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus) { cemu_assert_unimplemented(); return false; } virtual bool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus) { cemu_assert_unimplemented(); return false; } }; struct FSCVirtualFile { struct FSCDirIteratorState { sint32 index; std::vector dirEntries; }; FSCVirtualFile() { } virtual ~FSCVirtualFile() { if (dirIterator) delete dirIterator; } virtual sint32 fscGetType() { cemu_assert_unimplemented(); return 0; } virtual uint64 fscQueryValueU64(uint32 id) { cemu_assert_unimplemented(); return 0; } virtual uint32 fscWriteData(void* buffer, uint32 size) { cemu_assert_unimplemented(); return 0; } virtual uint32 fscReadData(void* buffer, uint32 size) { cemu_assert_unimplemented(); return 0; } virtual void fscSetSeek(uint64 seek) { cemu_assert_unimplemented(); } virtual uint64 fscGetSeek() { cemu_assert_unimplemented(); return 0; } virtual void fscSetFileLength(uint64 endOffset) { cemu_assert_unimplemented(); } virtual bool fscDirNext(FSCDirEntry* dirEntry) { cemu_assert_unimplemented(); return false; } virtual bool fscRewindDir() { cemu_assert_unimplemented(); return false; } FSCDirIteratorState* dirIterator{}; bool m_isAppend{ false }; }; #define FSC_PRIORITY_BASE (0) #define FSC_PRIORITY_AOC (1) #define FSC_PRIORITY_PATCH (2) #define FSC_PRIORITY_REDIRECT (3) #define FSC_PRIORITY_MAX (3) #define FSC_PRIORITY_COUNT (4) void fsc_init(); sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority=0); bool fsc_unmount(std::string_view mountPath, sint32 priority); void fsc_unmountAll(); FSCVirtualFile* fsc_open(const char* path, FSC_ACCESS_FLAG accessFlags, sint32* fscStatus, sint32 maxPriority=FSC_PRIORITY_MAX); FSCVirtualFile* fsc_openDirIterator(const char* path, sint32* fscStatus); bool fsc_createDir(const char* path, sint32* fscStatus); bool fsc_rename(const char* srcPath, const char* dstPath, sint32* fscStatus); bool fsc_remove(const char* path, sint32* fscStatus); bool fsc_nextDir(FSCVirtualFile* fscFile, FSCDirEntry* dirEntry); void fsc_close(FSCVirtualFile* fscFile); uint32 fsc_getFileSize(FSCVirtualFile* fscFile); uint32 fsc_getFileSeek(FSCVirtualFile* fscFile); void fsc_setFileSeek(FSCVirtualFile* fscFile, uint32 newSeek); void fsc_setFileLength(FSCVirtualFile* fscFile, uint32 newEndOffset); bool fsc_isDirectory(FSCVirtualFile* fscFile); bool fsc_isFile(FSCVirtualFile* fscFile); bool fsc_isWritable(FSCVirtualFile* fscFile); uint32 fsc_readFile(FSCVirtualFile* fscFile, void* buffer, uint32 size); uint32 fsc_writeFile(FSCVirtualFile* fscFile, void* buffer, uint32 size); uint8* fsc_extractFile(const char* path, uint32* fileSize, sint32 maxPriority = FSC_PRIORITY_MAX); std::optional> fsc_extractFile(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX); bool fsc_doesFileExist(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX); bool fsc_doesDirectoryExist(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX); // wud device bool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class FSTVolume* mountedVolume, sint32 priority); // wua device bool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class ZArchiveReader* archive, sint32 priority); // wuhb device bool FSCDeviceWUHB_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class WUHBReader* wuhbReader, sint32 priority); // hostFS device bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority); // redirect device void fscDeviceRedirect_map(); void fscDeviceRedirect_add(std::string_view virtualSourcePath, size_t fileSize, const fs::path& targetFilePath, sint32 priority);