Follows the video core PR. fmt doesn't require casts for enum classes
anymore, so we can remove quite a few casts.
Co-Authored-By: LC <712067+lioncash@users.noreply.github.com>
The deep recursion has caused issues in certain games with large numbers of files, especially with MSVC builds.
Previously the recursion depth is about equal to the number of files present. With this the depth should be about equal to the maximum depth of the directory structure of the RomFS.
We can adjust the API to allow std::size_t indices, which simplifies
operating with standard container types. It also prevents truncation
warnings from occurring in these cases as well.
Previously, we were returning a value that was way too big, causing an integer overflow in Fractured Souls.
According to wwylele, the biggest oberserved save size for 3DS is 1MB, so this new value should leave plenty of room, even if games use a bigger size.
You can now directly place ExeFS overrides/patches inside the mod folder (instead of the exefs subfolder). This allows us to have drop-in compatibility with Luma3DS mods.
The original path (file_name.exefsdir) is still supported, but alternatively users can choose to put exefs patches in the same place as LayeredFS files (`load/mods/<Title ID>/exefs`).
Only enabled for NCCHs that do not have an override romfs.
LayeredFS files should be put in the `load` directory in User Directory. The directory structure is similar to yuzu's but currently does not allow named mods yet. Replacement files should be put in `load/mods/<Title ID>/romfs` while patches/stubs should be put in `load/mods/<Title ID>/romfs_ext`.
This implementation is different from Luma3DS's which directly hooks the SDK functions. Instead, we read the RomFS's metadata and figure out the directory and file structure. Then, relocations (i.e. replacements/deletions/patches) are applied. Afterwards, we rebuild the metadata, and assign 'fake' data offsets to the files. When we want to read file data from this rebuilt RomFS, we use binary search to find the last data offset smaller or equal to the given offset and read from that file (either from the original RomFS, or from replacement files, or from buffered data with patches applied) and any later files when length is not enough.
The code that rebuilds the metadata is pretty complex and uses quite a few variables to keep track of necessary information like metadata offsets. According to my tests, it is able to build RomFS-es identical to the original (but without trailing garbage data) when no relocations are applied.