mirror of
https://github.com/MonsterDruide1/OdysseyDecomp
synced 2026-04-24 09:34:02 +00:00
249 lines
8.4 KiB
C++
249 lines
8.4 KiB
C++
#include "Project/File/FileLoader.h"
|
|
|
|
#include <filedevice/seadFileDeviceMgr.h>
|
|
#include <resource/seadArchiveRes.h>
|
|
#include <thread/seadDelegateThread.h>
|
|
|
|
#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<sead::ArchiveRes>(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
|