#include "Project/File/FileLoader.h" #include #include #include #include "Library/Base/StringUtil.h" #include "Library/File/FileUtil.h" #include "Library/Yaml/ByamlIter.h" #include "Project/ArchiveEntry.h" #include "Project/ArchiveHolder.h" #include "Project/File/FileLoaderThread.h" #include "Project/File/SoundItemEntry.h" #include "Project/File/SoundItemHolder.h" namespace al { static sead::SafeString sDeviceName{"main"}; FileLoader::FileLoader(s32 threadPriority) { mLoaderThread = new FileLoaderThread(threadPriority); mArchiveHolder = new ArchiveHolder(); mSoundItemHolder = new SoundItemHolder(); mFileDevice = sead::FileDeviceMgr::instance()->findDevice(sDeviceName); } u32 getFileList(sead::FixedSafeString<256> out[], s32 outSize, const char* path, bool isPathValid(const sead::DirectoryEntry&, const char*), const char* suffix) { u32 entriesRead; sead::FileDevice* mainFileDevice = sead::FileDeviceMgr::instance()->getMainFileDevice(); sead::DirectoryHandle handle; sead::FileDevice* fileDevice = mainFileDevice->tryOpenDirectory(&handle, path); if (!fileDevice) return 0; u32 entryCount = 0; sead::DirectoryEntry entry; for (s32 i = 0; i < outSize; i++) { entriesRead = 0; fileDevice->tryReadDirectory(&entriesRead, &handle, &entry, 1); if (entriesRead == 0) break; if (isPathValid(entry, suffix)) { out[entryCount] = entry.name; entryCount++; } } fileDevice->tryCloseDirectory(&handle); return entryCount; } static bool isDirectoryValid(const sead::DirectoryEntry& entry, const char* suffix) { return entry.is_directory; } u32 FileLoader::listSubdirectories(sead::FixedSafeString<256> out[], s32 outSize, const char* path) { return getFileList(out, outSize, path, &isDirectoryValid, nullptr); } static bool isFileValid(const sead::DirectoryEntry& entry, const char* suffix) { if (!suffix) return !entry.is_directory; s32 suffixLen = strlen(suffix); if (entry.name.getBufferSize() < suffixLen) return false; const char* pathStr = entry.name.cstr(); const char* pathSuffixStart = strrchr(pathStr, '.'); const char* pathSuffix = ""; if (pathSuffixStart && pathSuffixStart != pathStr) pathSuffix = pathSuffixStart + 1; return strcasecmp(pathSuffix, suffix) == 0; } u32 FileLoader::listFiles(sead::FixedSafeString<256> out[], s32 outSize, const char* path, const char* suffix) { return getFileList(out, outSize, path, &isFileValid, suffix); } bool FileLoader::isExistFile(const sead::SafeString& path, sead::FileDevice* device) const { sead::FileDevice* fileDevice = getFileDevice(path, device); bool isExist = false; fileDevice->tryIsExistFile(&isExist, path); return isExist; } sead::FileDevice* FileLoader::getFileDevice(const sead::SafeString& path, sead::FileDevice* device) const { return device ?: mFileDevice; } bool FileLoader::isExistArchive(const sead::SafeString& path, sead::FileDevice* device) const { return isExistFile(path, device); } bool FileLoader::isExistDirectory(const sead::SafeString& path, sead::FileDevice* device) const { sead::FileDevice* fileDevice = getFileDevice(path, device); bool isExist = false; fileDevice->tryIsExistDirectory(&isExist, path); return isExist; } u32 FileLoader::getFileSize(const sead::SafeString& path, sead::FileDevice* device) const { sead::FileDevice* fileDevice = getFileDevice(path, device); u32 fileSize = 0; fileDevice->tryGetFileSize(&fileSize, path); return fileSize; } u8* FileLoader::loadFile(const sead::SafeString& path, s32 alignment, sead::FileDevice* device) { sead::FileDevice::LoadArg loadArg; loadArg.alignment = alignment; loadArg.path = path; return getFileDevice(path, device)->tryLoad(loadArg); } bool FileLoader::tryLoadFileToBuffer(const sead::SafeString& path, u8* buffer, u32 bufferSize, s32 alignment, sead::FileDevice* device) { sead::FileDevice::LoadArg loadArg; loadArg.path = path; loadArg.buffer = buffer; loadArg.buffer_size = bufferSize; loadArg.buffer_size_alignment = alignment; return getFileDevice(path, device)->tryLoad(loadArg) != nullptr; } sead::ArchiveRes* FileLoader::loadArchive(const sead::SafeString& path, sead::FileDevice* device) { return loadArchiveLocal(path, nullptr, device); } sead::ArchiveRes* FileLoader::loadArchiveLocal(const sead::SafeString& path, const char* suffix, sead::FileDevice* device) { ArchiveEntry* entry = mArchiveHolder->tryFindEntry(path); if (entry) { if (entry->getFileState() != FileState::IsLoadDone) entry->waitLoadDone(); } else if (!sead::ThreadMgr::instance()->isMainThread()) { sead::Heap* heap = sead::HeapMgr::instance()->getCurrentHeap(); entry = requestLoadArchive(path, heap, getFileDevice(path, device)); entry->waitLoadDone(); } else { sead::ResourceMgr::LoadArg loadArg; loadArg.device = getFileDevice(path, device); loadArg.path = path; loadArg.load_data_alignment = calcFileAlignment(path); loadArg.load_data_buffer_alignment = calcBufferSizeAlignment(path); sead::Resource* resource = sead::ResourceMgr::instance()->tryLoad(loadArg, suffix ? suffix : "sarc", nullptr); return sead::DynamicCast(resource); } return entry->getArchiveRes(); } sead::ArchiveRes* FileLoader::loadArchiveWithExt(const sead::SafeString& path, const char* suffix, sead::FileDevice* device) { return loadArchiveLocal(path, suffix, device); } bool FileLoader::tryRequestLoadArchive(const sead::SafeString& path, sead::Heap* heap, sead::FileDevice* device) { if (mArchiveHolder->tryFindEntry(path)) return false; requestLoadArchive(path, heap, device); return true; } ArchiveEntry* FileLoader::requestLoadArchive(const sead::SafeString& path, sead::Heap* heap, sead::FileDevice* device) { ArchiveEntry* entry = mArchiveHolder->addNewLoadRequestEntry(path, heap, getFileDevice(path, device)); mLoaderThread->requestLoadFile(entry); return entry; } bool FileLoader::loadSoundItem(u32 itemId, u32 unknown, IAudioResourceLoader* loader) { SoundItemEntry* entry = mSoundItemHolder->tryFindEntry(itemId, loader); if (!entry) { entry = requestLoadSoundItem(itemId, unknown, loader); entry->waitLoadDone(); } else if (entry->getFileState() != FileState::IsLoadDone) { entry->waitLoadDone(); } return entry->isLoadSuccess(); } SoundItemEntry* FileLoader::requestLoadSoundItem(u32 itemId, u32 unknown, IAudioResourceLoader* loader) { SoundItemEntry* entry = mSoundItemHolder->addNewLoadRequestEntry(itemId, unknown, loader); mLoaderThread->requestLoadFile(entry); return entry; } bool FileLoader::tryRequestLoadSoundItem(u32 itemId, IAudioResourceLoader* loader) { if (mSoundItemHolder->tryFindEntry(itemId, loader)) return false; requestLoadSoundItem(itemId, -1, loader); return true; } void FileLoader::requestPreLoadFile(const ByamlIter& preLoadList, sead::Heap* heap, IAudioResourceLoader* loader) { if (mIsFilePreloaded) return; for (s32 i = 0; i < preLoadList.getSize(); i++) { ByamlIter iter; preLoadList.tryGetIterByIndex(&iter, i); const char* type; iter.tryGetStringByKey(&type, "Type"); if (!isEqualString(type, "SoundItem") && isEqualString(type, "Archive")) { const char* path; iter.tryGetStringByKey(&path, "Path"); tryRequestLoadArchive(path, heap, nullptr); } } mIsFilePreloaded = true; } void FileLoader::waitLoadDoneAllFile() { mArchiveHolder->waitLoadDoneAll(); } void FileLoader::clearAllEntry() { mArchiveHolder->clearEntry(); mSoundItemHolder->clearEntry(); mIsFilePreloaded = false; } void FileLoader::setThreadPriority(s32 priority) { mLoaderThread->getThread()->setPriority(priority); } } // namespace al