diff options
| author | robojumper <robojumper@gmail.com> | 2024-05-25 19:30:32 +0200 |
|---|---|---|
| committer | robojumper <robojumper@gmail.com> | 2024-06-02 00:06:17 +0200 |
| commit | 6da4bb94c539f71ee3ef4c5d79c789127b70ddaf (patch) | |
| tree | c94205374332e0b5c658068fbaa0525a04733c0d /src/d/d_rawarchive.cpp | |
| parent | fda931e2aead6b77c099f0e09d34ebd17c2d238c (diff) | |
d_rawarchive mostly matching
Diffstat (limited to 'src/d/d_rawarchive.cpp')
| -rw-r--r-- | src/d/d_rawarchive.cpp | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/src/d/d_rawarchive.cpp b/src/d/d_rawarchive.cpp new file mode 100644 index 00000000..db540865 --- /dev/null +++ b/src/d/d_rawarchive.cpp @@ -0,0 +1,430 @@ +#include <d/d_rawarchive.h> +#include <rvl/VI.h> +// clang-format off +#include <MSL_C/string.h> +// clang-format on + + +class UnkManager { +public: + /* vtable at 8050df50 */ + /** 800651c0 */ + virtual void CreateArc(void *data, const char *path); + /** 800653d0 */ + virtual void DestroyArc(const char *path); + + u32 stage; +}; + +extern "C" int fn_80061B10(void *d, u32 len) { + u32 *data = (u32*)d; + u32 result = 0; + // Compiler will unroll this loop + for (u32 len_words = len / 4; len_words != 0; len_words--) { + result += *data++; + } + return result; +} + +extern "C" int fn_80061BA0(void *data, u32 len) { + int result = fn_80061B10(data, len); + return result != 0 ? result : -1; +} + +extern "C" void fn_80061BE0(UnkManager *mgr, const char *name, size_t len) { + // Sets stage to all spaces + mgr->stage = 0x20202020; + // copies the stage name? + memcpy((char*)&mgr->stage, name, len); +} + +dRawArcEntry_c::dRawArcEntry_c() { + mArcName[0] = '\0'; + mRefCount = 0; + mpDvdReq = nullptr; + mpArc = nullptr; + mpCommandHeap = nullptr; + mpData = nullptr; + mChecksum = 0; + mpFrmHeap = 0; +} + +dRawArcEntry_c::~dRawArcEntry_c() { + // Wait for request to complete before destroying + if (mpDvdReq->mStatus == 0) { + do { + VIWaitForRetrace(); + } while (mpDvdReq->mStatus == 0); + } + destroy(nullptr); +} + + +void dRawArcEntry_c::searchCallback(void *arg, void *data, const ARCDirEntry *entry, const char *path, bool ctrl) { + UnkManager *mgr = (UnkManager *)arg; + if (entry->isDir) { + int len = strlen(entry->name); + fn_80061BE0(mgr, entry->name, len <= 4 ? len : 4); + } else { + // dolphin: arg vtable at 8050df50 + // any others? + if (ctrl) { + mgr->CreateArc(data, path); + // branch to 800651c0, sets up room + } else { + mgr->DestroyArc(path); + // branch to 800653d0, destroys room + } + } +} + +void dRawArcEntry_c::searchCallback1(void *a, void *b, const ARCDirEntry *c, const char *d) { + searchCallback(a, b, c, d, true); +} + +void dRawArcEntry_c::searchCallback2(void *a, void *b, const ARCDirEntry *c, const char *d) { + searchCallback(a, b, c, d, false); +} + + +bool dRawArcEntry_c::destroy(void *arg) { + if (mpDvdReq != nullptr) { + if (mpDvdReq->mStatus == 0) { + // Can't destroy if the request is still ongoing + return false; + } + mpArc = mpDvdReq->mDataPtr; + mpData = mpDvdReq->getArcBinary(); + mAmountRead = mpDvdReq->mAmountRead; + mpCommandHeap = mpDvdReq->mHeap; + mpDvdReq->do_delete(); + mpDvdReq = nullptr; + } + + if (mpArc != nullptr) { + if (arg != nullptr) { + mpArc->searchInside(searchCallback2, arg); + } + + if (mpFrmHeap != nullptr) { + mHeap::destroyFrmHeap(mpFrmHeap); + mpFrmHeap = nullptr; + } + mpArc->unmount(); + mpArc = nullptr; + } + + if (mpData != nullptr) { + EGG::Heap::free(mpData, nullptr); + mpData = nullptr; + } + + mAmountRead = 0; + mChecksum = 0; + mpCommandHeap = 0; + return true; +} + +bool dRawArcEntry_c::loadArcFromDiskChecked(const char *fileName, const char *dirName, u8 mountDirection, + EGG::Heap *heap) { + char arcPath[128]; + arcPath[0] = '\0'; + + if (checkArcExistsOnDiskInner(arcPath, fileName, dirName)) { + return loadArcFromDisk(fileName, arcPath, mountDirection, heap); + } + return false; +} + +// Regswap +inline void inline_strncat(char *dest, const char *src, size_t destSize) { + if (src != nullptr) { + size_t destLen = strlen(dest); + size_t srcLen = strlen(src); + size_t count = destLen + srcLen + 1 >= destSize ? destSize - destLen - 1 : srcLen; + strncpy(dest + destLen, src, count); + size_t offset = destLen + count; + dest[offset] = '\0'; + } +} + +inline void inline_strncpy(char *dest, const char *src, size_t destSize) { + if (src != dest) { + dest[0] = '\0'; + inline_strncat(dest, src, destSize); + } +} + +bool dRawArcEntry_c::loadArcFromDisk(const char *arcName, const char *arcPath, u8 mountDirection, EGG::Heap *heap) { + mpDvdReq = mDvd_mountMemArchive_c::create(arcPath, mountDirection, heap); + if (mpDvdReq == nullptr) { + return false; + } + inline_strncpy(mArcName, arcName, sizeof(mArcName)); + return true; +} + +bool dRawArcEntry_c::checkArcExistsOnDisk(const char *fileName, const char *dirName) { + char path[128]; + path[0] = '\0'; + return checkArcExistsOnDiskInner(path, fileName, dirName); +} + +// sprintf2 +extern "C" void fn_8003D650(char *out, const char *fmt, ...); + +bool dRawArcEntry_c::checkArcExistsOnDiskInner(char *outBuf, const char *fileName, const char *dirName) { + fn_8003D650(outBuf, "/US/%s/%s.arc", dirName, fileName); + if (!mDvd::IsExistPath(outBuf)) { + fn_8003D650(outBuf, "/%s/%s.arc", dirName, fileName); + if (!mDvd::IsExistPath(outBuf)) { + return false; + } + } + return true; +} + +int dRawArcEntry_c::mount(const char *name, void *data, void *callbackArg, u8 mountDirection, EGG::Heap *heap) { + inline_strncpy(mArcName, name, sizeof(mArcName)); + // TODO this conditional uses a few more instructions in the original binary + mpArc = EGG::Archive::mount(data, heap, mountDirection != 1 ? 4 : -4); + if (mpArc == nullptr) { + return -1; + } else { + int result = onMount(callbackArg); + int ret = 0; + if (result == -1) { + ret = result; + } + return ret; + } +} + +int dRawArcEntry_c::ensureLoadedMaybe(void *callbackArg) { + if (mpArc == nullptr) { + if (mpDvdReq == nullptr) { + return -1; + } + + if (mpDvdReq->mStatus == 0) { + return 1; + } + + mpArc = mpDvdReq->mDataPtr; + mpData = mpDvdReq->getArcBinary(); + mAmountRead = mpDvdReq->mAmountRead; + if (mpData != nullptr) { + u32 blockSize = EGG::ExpHeap::getSizeForMBlock(mpData); + if (mAmountRead != blockSize) { + mAmountRead = blockSize; + } + } + + mpCommandHeap = mpDvdReq->mHeap; + mpDvdReq->do_delete(); + mpDvdReq = nullptr; + if (mpArc == nullptr) { + return -1; + } + mpFrmHeap = mHeap::makeHeapOnCurrentGameHeap(-1, this->mArcName, 0x20, 0); + if (mpFrmHeap == nullptr) { + return -1; + } + int result = onMount(callbackArg); + mHeap::restoreCurrentHeap(); + mHeap::adjustFrmHeap(mpFrmHeap); + mChecksum = fn_80061BA0(mpData, mAmountRead); + if (result == -1) { + return result; + } + DCStoreRange(mpFrmHeap, mpFrmHeap->mHeapHandle->end - (u8*)mpFrmHeap); + } + + return 0; +} + +int dRawArcEntry_c::onMount(void *callbackArg) { + mpArc->countFile(); + if (callbackArg != nullptr) { + mpArc->searchInside(searchCallback1, callbackArg); + } + return 0; +} + + +dRawArcTable_c::dRawArcTable_c() { + mpEntries = nullptr; + mCount = 0; + mCallbackArg = nullptr; +} + +dRawArcTable_c::~dRawArcTable_c() { + if (mpEntries) { + delete[] mpEntries; + mpEntries = nullptr; + mCount = 0; + } +} + +bool dRawArcTable_c::init(u16 count, void *callbackArg, EGG::Heap *heap) { + mpEntries = new (heap, 0x04) dRawArcEntry_c[count](); + if (mpEntries == nullptr) { + return false; + } + + mCount = count; + mCallbackArg = callbackArg; + return true; +} + +bool dRawArcTable_c::getArcOrLoadFromDisk(const char *name, const char *dirName, u8 mountDirection, EGG::Heap *heap) { + dRawArcEntry_c *entry = findEntry(name); + if (entry == nullptr) { + entry = findEmptySlot(); + if (entry == nullptr) { + return false; + } + bool result = entry->loadArcFromDiskChecked(name, dirName, mountDirection, heap); + if (!result) { + entry->destroy(mCallbackArg); + return false; + } + } + entry->increaseRefCount(); + return true; +} + +bool dRawArcTable_c::addEntryFromSuperArc(const char *name, void *data, u8 mountDirection, EGG::Heap *heap) { + dRawArcEntry_c *entry = findEntry(name); + if (entry == nullptr) { + entry = findEmptySlot(); + if (entry == nullptr) { + return false; + } + int result = entry->mount(name, data, mCallbackArg, mountDirection, heap); + if (result != 0) { + entry->destroy(mCallbackArg); + return false; + } + } + entry->increaseRefCount(); + return true; +} + +int dRawArcTable_c::ensureLoadedMaybe2(const char *name) { + dRawArcEntry_c *entry = findEntry(name); + if (entry == nullptr) { + return -2; + } + return entry->ensureLoadedMaybe(mCallbackArg); +} + +int dRawArcTable_c::ensureLoadedMaybe(const char *name) { + dRawArcEntry_c *entry = findEntry(name); + if (entry == nullptr) { + return -2; + } + return entry->ensureLoadedMaybe(mCallbackArg); +} + +bool dRawArcTable_c::hasEntry(const char *name) { + return findEntry(name) != nullptr; +} + +bool dRawArcTable_c::decreaseRefCount(const char *name) { + dRawArcEntry_c *entry = findEntry(name); + if (entry == nullptr) { + return false; + } + entry->decreaseRefCount(); + if (!entry->isReferenced()) { + entry->destroy(mCallbackArg); + } + return true; +} + +void *dRawArcTable_c::getDataFromOarc(const char *name, const char *path) { + void *data = nullptr; + dRawArcEntry_c *entry = findLoadedEntry(name); + if (entry != nullptr) { + EGG::Archive *arc = entry->getArc(); + if (arc != nullptr) { + data = arc->getFile(path, nullptr); + } + } + return data; +} + +void *dRawArcTable_c::getSubEntryData(const char *name, const char *path) { + void *data = nullptr; + dRawArcEntry_c *entry = findLoadedEntry(name); + if (entry != nullptr) { + EGG::Archive *arc = entry->getArc(); + if (arc != nullptr) { + int num = arc->convertPathToEntryID(path); + if (num >= 0) { + data = arc->getFileFast(num, nullptr); + } + } + } + return data; +} + +void *dRawArcTable_c::getLoadedArcData(const char *name) { + dRawArcEntry_c *entry = findLoadedEntry(name); + return entry == nullptr ? nullptr : entry->getData(); +} + +int dRawArcTable_c::ensureAllEntriesLoaded() { + dRawArcEntry_c *entry = mpEntries; + int result = 0; + for (int i = 0; i < mCount; i++) { + if (entry->isLoading()) { + result = entry->ensureLoadedMaybe(mCallbackArg); + if (result != 0) { + return result; + } + } + entry++; + } + + return 0; +} + + +extern "C" bool strequals(const char *, const char*); + +// TODO the load from self can happen earlier +dRawArcEntry_c *dRawArcTable_c::findEntry(const char *name) const { + dRawArcEntry_c *entry = mpEntries; + for (int i = 0; i < mCount; i++) { + if (entry->isReferenced() && strequals(entry->name(), name)) { + return entry; + } + entry++; + } + + return nullptr; +} + +dRawArcEntry_c *dRawArcTable_c::findEmptySlot() { + dRawArcEntry_c *entry = mpEntries; + for (int i = 0; i < mCount; i++) { + if (!entry->isReferenced()) { + return entry; + } + entry++; + } + + return nullptr; +} + +dRawArcEntry_c *dRawArcTable_c::findLoadedEntry(const char *name) { + dRawArcEntry_c *entry = findEntry(name); + if (entry == nullptr) { + return nullptr; + } else if (entry->isNotLoaded()) { + return nullptr; + } + return entry; +} |
