diff options
| author | robojumper <robojumper@gmail.com> | 2024-05-20 23:22:31 +0200 |
|---|---|---|
| committer | robojumper <robojumper@gmail.com> | 2024-05-20 23:22:31 +0200 |
| commit | c1ca74d657fb11b67435d6e5679ab6482c4c5516 (patch) | |
| tree | d5d4bbf2042007d3b3cdf15b9566cbd8dbe5f837 /src/DynamicLink.cpp | |
| parent | 725e43dd690968e66631c3e38c3f477c656fd271 (diff) | |
DynamicLink
Diffstat (limited to 'src/DynamicLink.cpp')
| -rw-r--r-- | src/DynamicLink.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/DynamicLink.cpp b/src/DynamicLink.cpp new file mode 100644 index 00000000..2898ab14 --- /dev/null +++ b/src/DynamicLink.cpp @@ -0,0 +1,373 @@ +#include <DynamicLink.h> + +DynamicModuleControlBase *DynamicModuleControlBase::mFirst; +DynamicModuleControlBase *DynamicModuleControlBase::mLast; + +DynamicModuleControlBase::~DynamicModuleControlBase() { + if (mPrev != nullptr) { + mPrev->mNext = mNext; + } + if (mNext != nullptr) { + mNext->mPrev = mPrev; + } + if (mFirst == this) { + mFirst = mNext; + } + if (mLast == this) { + mLast = mPrev; + } + mNext = nullptr; + mPrev = nullptr; +} + +DynamicModuleControlBase::DynamicModuleControlBase() { + mLinkCount = 0; + mDoLinkCount = 0; + mNext = nullptr; + if (mFirst == nullptr) { + mFirst = this; + } + DynamicModuleControlBase *last = mLast; + mPrev = last; + if (last != nullptr) { + last->mNext = this; + } + mLast = this; +} + +BOOL DynamicModuleControlBase::link() { + if (mLinkCount == 0) { + do_load(); + if (!do_link()) { + return false; + } + + if (mDoLinkCount < 0xFFFF) { + mDoLinkCount++; + } + } + + if (mLinkCount < 0xFFFF) { + mLinkCount++; + } + + return true; +} + +BOOL DynamicModuleControlBase::unlink() { + if (mLinkCount != 0) { + if (mLinkCount < 0xFFFF && --mLinkCount == 0) { + do_unlink(); + do_unload(); + } + } + + return true; +} + +BOOL DynamicModuleControlBase::load_async() { + if (mLinkCount == 0) { + return do_load_async(); + } + return true; +} + +const char *DynamicModuleControlBase::getModuleName() const { + return nullptr; +} + +int DynamicModuleControlBase::getModuleSize() const { + return 0; +} + +const char *DynamicModuleControlBase::getModuleTypeString() const { + return "Base"; +} + +void DynamicModuleControlBase::dump() {} + +bool DynamicModuleControlBase::do_load() { + return true; +} + +BOOL DynamicModuleControlBase::do_load_async() { + return true; +} + +bool DynamicModuleControlBase::do_unload() { + return true; +} + +BOOL DynamicModuleControlBase::do_link() { + return true; +} + +bool DynamicModuleControlBase::do_unlink() { + return true; +} + +u32 DynamicModuleControl::sAllocBytes; +mDvd_toMainRam_base_c *DynamicModuleControl::sDvdFile; +EGG::ExpHeap *DynamicModuleControl::sDylinkHeap; +u32 DynamicModuleControl::sCurrentAllocatableSize; +u32 DynamicModuleControl::sTotalFreeSize; +EGG::Archive *DynamicModuleControl::sArchive; + +DynamicModuleControl::DynamicModuleControl(const char *name, EGG::ExpHeap *heap) + : mModule(nullptr), mBss(nullptr), unk_24(0), mName(name), mResourceType(0), unk_33(0), unk_40(0), + mDvdCallbackRequest(0), mHeap(heap), mpRelMapFile() {} + +DynamicModuleControl::~DynamicModuleControl() {} + +const char *DynamicModuleControl::getModuleName() const { + return mName; +} + +void DynamicModuleControl::initialize(EGG::ExpHeap *heap) { + sDylinkHeap = heap; + sCurrentAllocatableSize = heap->getAllocatableSize(4); + sTotalFreeSize = heap->getTotalFreeSize(); +} + +bool DynamicModuleControl::callback(void *arg) { + return static_cast<DynamicModuleControl *>(arg)->do_load(); +} + +void DynamicModuleControl::checkHeapStatus() { + if (mHeap == sDylinkHeap) { + int size = mHeap->getAllocatableSize(4); + if (sCurrentAllocatableSize > size) { + sCurrentAllocatableSize = size; + } + size = mHeap->getTotalFreeSize(); + if (sTotalFreeSize > size) { + sTotalFreeSize = size; + } + } +} + +const char *DynamicModuleControl::sRelsDir = "/rels"; + +bool DynamicModuleControl::do_load() { + char buf[64]; + if (mModule != nullptr) { + return true; + } + if (mHeap == nullptr) { + mHeap = sDylinkHeap; + } + snprintf(buf, sizeof(buf), "%s/%sNP.rel", sRelsDir, mName); + if (mModule == nullptr) { + if (sArchive != nullptr) { + sDvdFile = fn_802EFE90(sArchive, buf, 1, mHeap); + } else { + sDvdFile = fn_802F0030(buf, 1, mHeap); + } + + if (sDvdFile != nullptr) { + sDvdFile->waitUntilDone(); + checkHeapStatus(); + void *ptr = sDvdFile->mDataPtr; + sDvdFile->mDataPtr = nullptr; + mModule = static_cast<OSModuleHeader *>(ptr); + fn_802EF480(sDvdFile); + sDvdFile = nullptr; + if (mModule != nullptr) { + unk_40 = 0; + mResourceType = 3; + } + } + } + + if (mModule == nullptr) { + return false; + } + if (unk_33 < 0xFF) { + unk_33++; + } + checkHeapStatus(); + return true; +} + +BOOL DynamicModuleControl::do_load_async() { + if (mDvdCallbackRequest == nullptr) { + if (mModule != nullptr) { + return true; + } + mDvdCallbackRequest = mDvd_callback_c::create(callback, this); + } + + if (mDvdCallbackRequest != nullptr && mDvdCallbackRequest->mStatus != 0) { + fn_802EF480(mDvdCallbackRequest); + mDvdCallbackRequest = nullptr; + return true; + } else { + return false; + } +} + +bool DynamicModuleControl::do_unload() { + if (mModule != nullptr) { + mHeap->free(mModule); + mModule = nullptr; + } + + return true; +} + +void DynamicModuleControl::dump() {} + +BOOL DynamicModuleControl::do_link() { + char mapPath[64]; + + if (mModule != nullptr) { + int alignedFixSize = ROUND_UP(mModule->fixSize, 0x20); + int alignedFixPtr = (int)&mModule->info + alignedFixSize; + int totalSize = EGG::ExpHeap::getSizeForMBlock(mModule); + BOOL result; + if (totalSize == 0) { + void *bss = mHeap->alloc(mModule->bssSize, 0x20); + if (bss == nullptr) { + goto error; + } + mBss = bss; + result = OSLink(&mModule->info, bss); + if (!result) { + goto error; + } + } else { + if (alignedFixSize + mModule->bssSize < totalSize) { + result = OSLinkFixed(&mModule->info, (void *)alignedFixPtr); + if (!result) { + goto error; + } + mHeap->resizeForMBlock(mModule, alignedFixSize + mModule->bssSize); + } else if ((int)mHeap->resizeForMBlock(mModule, alignedFixSize + mModule->bssSize) > 0) { + // TODO resizeForMBlock should maybe return int? + result = OSLinkFixed(&mModule->info, (void *)alignedFixPtr); + if (!result) { + goto error; + } + } else { + void *bss = mHeap->alloc(mModule->bssSize, 0x20); + if (!bss) { + goto error; + } + mBss = bss; + result = OSLinkFixed(&mModule->info, bss); + if (!result) { + goto error; + } + mHeap->resizeForMBlock(mModule, alignedFixSize); + } + } + + sAllocBytes = sAllocBytes + getModuleSize(); + snprintf(mapPath, sizeof(mapPath), "%s/%sNP.map", "/maps", mName); + mpRelMapFile.RegisterOnDvd(mapPath, &mModule->info); + unk_24 = ((UNKWORD(*)())mModule->prolog)(); + checkHeapStatus(); + return true; + } + +error: + unk_33 = 0; + if (mBss != nullptr) { + mHeap->free(mBss); + mBss = nullptr; + } + if (mModule != nullptr) { + mHeap->free(mModule); + mModule = nullptr; + } + return false; +} + +bool DynamicModuleControl::do_unlink() { + ((void (*)())mModule->epilog)(); + mpRelMapFile.Unregister(); + if (!OSUnlink(&mModule->info)) { + return false; + } + sAllocBytes -= getModuleSize(); + if (mBss != nullptr) { + mHeap->free(mBss); + mBss = nullptr; + } + return true; +} + +int DynamicModuleControl::getModuleSize() const { + if (mModule != nullptr) { + int size = EGG::ExpHeap::getSizeForMBlock(mModule); + if (mBss != nullptr) { + size += mModule->bssSize; + } + + return size; + } + return 0; +} + +const char *DynamicModuleControl::getModuleTypeString() const { + static const char *REL_LOAD_TYPES[4] = { + "????", + "MEM", + "ARAM", + "DVD", + }; + return REL_LOAD_TYPES[mResourceType & 3]; +} + +DbMapFile::~DbMapFile() { + if (unk_0) { + Unregister(); + } +} + +namespace nw4r { +namespace db { +// TODO +typedef struct MapFile { +} MapFile; +extern MapFile *MapFile_RegistOnDvd(void *arg, const char *buf, const OSModuleInfo *info); +extern void *MapFile_Unregist(MapFile *); +} // namespace db +} // namespace nw4r + +void DbMapFile::RegisterOnDvd(const char *path, const OSModuleInfo *info) { + if (mDvd::IsExistPath(path)) { + unk_0 = (UNKWORD)nw4r::db::MapFile_RegistOnDvd(((int *)this) + 1, path, info); + } else { + unk_0 = 0xffffffff; + } +} + +void DbMapFile::Unregister() { + if (unk_0 != 0) { + if (unk_0 != 0xffffffff) { + nw4r::db::MapFile_Unregist((nw4r::db::MapFile *)unk_0); + } + unk_0 = 0; + } +} +/* +// probably part of a different file +extern "C" void ModuleProlog() {} + +extern "C" void ModuleEpilog() {} + +extern "C" void ModuleUnresolved() {} + +extern "C" void ModuleConstructorsX(void (**ptrs)()) { + for (; *ptrs != nullptr; ptrs++) { + (*ptrs)(); + } +} + +extern "C" void ModuleDestructorsX(void (**ptrs)()) { + for (; *ptrs != nullptr; ptrs++) { + (*ptrs)(); + } +} +*/ |
