summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrobojumper <robojumper@gmail.com>2024-05-25 19:30:32 +0200
committerrobojumper <robojumper@gmail.com>2024-06-02 00:06:17 +0200
commit6da4bb94c539f71ee3ef4c5d79c789127b70ddaf (patch)
treec94205374332e0b5c658068fbaa0525a04733c0d /src
parentfda931e2aead6b77c099f0e09d34ebd17c2d238c (diff)
d_rawarchive mostly matching
Diffstat (limited to 'src')
-rw-r--r--src/d/d_rawarchive.cpp430
-rw-r--r--src/m/m_heap.cpp2
2 files changed, 431 insertions, 1 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;
+}
diff --git a/src/m/m_heap.cpp b/src/m/m_heap.cpp
index ca18857f..5220d771 100644
--- a/src/m/m_heap.cpp
+++ b/src/m/m_heap.cpp
@@ -207,6 +207,6 @@ EGG::AssertHeap *mHeap::createAssertHeap(EGG::Heap *parent) {
return g_assertHeap;
}
-EGG::Heap *mHeap::makeHeapOnCurrentGameHeap(size_t size, const char *name, u32 align, u32 flags) {
+EGG::FrmHeap *mHeap::makeHeapOnCurrentGameHeap(size_t size, const char *name, u32 align, u32 flags) {
return makeFrmHeapAndUpdate(size, g_gameHeaps[0], name, align, flags);
}