mirror of
https://github.com/zeldaret/ss
synced 2026-05-23 23:05:20 -04:00
365 lines
8.9 KiB
C++
365 lines
8.9 KiB
C++
#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();
|
|
}
|
|
|
|
void *DynamicModuleControl::callback(void *arg) {
|
|
return reinterpret_cast<void *>(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 = mDvd_toMainRam_arc_c::createOrDie(sArchive, buf, 1, mHeap);
|
|
} else {
|
|
sDvdFile = mDvd_toMainRam_normal_c::createOrDie(buf, 1, mHeap);
|
|
}
|
|
|
|
if (sDvdFile != nullptr) {
|
|
sDvdFile->waitUntilDone();
|
|
checkHeapStatus();
|
|
void *ptr = sDvdFile->mDataPtr;
|
|
sDvdFile->mDataPtr = nullptr;
|
|
mModule = static_cast<OSModuleHeader *>(ptr);
|
|
sDvdFile->do_delete();
|
|
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->isDone()) {
|
|
mDvdCallbackRequest->do_delete();
|
|
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 + 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 (mMapFileHandle != nullptr) {
|
|
Unregister();
|
|
}
|
|
}
|
|
|
|
void DbMapFile::RegisterOnDvd(const char *path, const OSModuleInfo *info) {
|
|
if (mDvd::IsExistPath(path)) {
|
|
mMapFileHandle = nw4r::db::MapFile_RegistOnDvd(&mMapFile, path, info);
|
|
} else {
|
|
mMapFileHandle = (nw4r::db::MapFileHandle)0xffffffff;
|
|
}
|
|
}
|
|
|
|
void DbMapFile::Unregister() {
|
|
if (mMapFileHandle != nullptr) {
|
|
if ((u32)mMapFileHandle != 0xffffffff) {
|
|
nw4r::db::MapFile_Unregist(mMapFileHandle);
|
|
}
|
|
mMapFileHandle = nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void ModuleProlog() {}
|
|
|
|
void ModuleEpilog() {}
|
|
|
|
void ModuleUnresolved() {}
|
|
|
|
void ModuleConstructorsX(void (**ptrs)()) {
|
|
for (; *ptrs != nullptr; ptrs++) {
|
|
(*ptrs)();
|
|
}
|
|
}
|
|
|
|
void ModuleDestructorsX(void (**ptrs)()) {
|
|
for (; *ptrs != nullptr; ptrs++) {
|
|
(*ptrs)();
|
|
}
|
|
}
|
|
}
|