From 1040e0498cb0a10bc8ed79a167d690d78f05dbd6 Mon Sep 17 00:00:00 2001 From: Jcw87 Date: Mon, 18 Sep 2023 12:29:20 -0700 Subject: [PATCH] JKRMemArchive, JKRAramArchive, JKRDvdArchive, JKRCompArchive (#54) * JKRMemArchive * JKRAramArchive * JKRDvdArchive * JKRCompArchive --- configure.py | 12 +- include/JSystem/JKernel/JKRAram.h | 6 +- include/JSystem/JKernel/JKRDvdAramRipper.h | 10 +- include/JSystem/JKernel/JKRMemArchive.h | 5 +- src/JSystem/JKernel/JKRAramArchive.cpp | 295 +++++++++++++++- src/JSystem/JKernel/JKRCompArchive.cpp | 378 ++++++++++++++++++++- src/JSystem/JKernel/JKRDvdArchive.cpp | 353 ++++++++++++++++++- src/JSystem/JKernel/JKRMemArchive.cpp | 233 +++++++++++-- 8 files changed, 1203 insertions(+), 89 deletions(-) diff --git a/configure.py b/configure.py index 7b2a9170e..27d405964 100644 --- a/configure.py +++ b/configure.py @@ -755,26 +755,26 @@ config.libs = [ JSystemLib( "JKernel", [ - Object(Matching, "JSystem/JKernel/JKRHeap.cpp"), + Object(Matching, "JSystem/JKernel/JKRHeap.cpp"), Object(NonMatching, "JSystem/JKernel/JKRStdHeap.cpp"), Object(NonMatching, "JSystem/JKernel/JKRExpHeap.cpp"), Object(NonMatching, "JSystem/JKernel/JKRSolidHeap.cpp"), - Object(Matching, "JSystem/JKernel/JKRDisposer.cpp"), - Object(Matching, "JSystem/JKernel/JKRThread.cpp"), + Object(Matching, "JSystem/JKernel/JKRDisposer.cpp"), + Object(Matching, "JSystem/JKernel/JKRThread.cpp"), Object(NonMatching, "JSystem/JKernel/JKRAram.cpp"), Object(NonMatching, "JSystem/JKernel/JKRAramHeap.cpp"), Object(NonMatching, "JSystem/JKernel/JKRAramBlock.cpp"), Object(NonMatching, "JSystem/JKernel/JKRAramPiece.cpp"), Object(NonMatching, "JSystem/JKernel/JKRAramStream.cpp"), - Object(Matching, "JSystem/JKernel/JKRFileLoader.cpp"), + Object(Matching, "JSystem/JKernel/JKRFileLoader.cpp"), Object(NonMatching, "JSystem/JKernel/JKRFileFinder.cpp"), Object(NonMatching, "JSystem/JKernel/JKRFileCache.cpp"), Object(NonMatching, "JSystem/JKernel/JKRArchivePub.cpp"), Object(NonMatching, "JSystem/JKernel/JKRArchivePri.cpp"), - Object(NonMatching, "JSystem/JKernel/JKRMemArchive.cpp"), + Object(Matching, "JSystem/JKernel/JKRMemArchive.cpp"), Object(NonMatching, "JSystem/JKernel/JKRAramArchive.cpp"), Object(NonMatching, "JSystem/JKernel/JKRDvdArchive.cpp"), - Object(NonMatching, "JSystem/JKernel/JKRCompArchive.cpp"), + Object(Matching, "JSystem/JKernel/JKRCompArchive.cpp"), Object(Matching, "JSystem/JKernel/JKRFile.cpp"), Object(NonMatching, "JSystem/JKernel/JKRDvdFile.cpp"), Object(NonMatching, "JSystem/JKernel/JKRDvdRipper.cpp"), diff --git a/include/JSystem/JKernel/JKRAram.h b/include/JSystem/JKernel/JKRAram.h index 18269423a..07f6bb231 100644 --- a/include/JSystem/JKernel/JKRAram.h +++ b/include/JSystem/JKernel/JKRAram.h @@ -36,7 +36,7 @@ public: static JKRAram* create(u32, u32, long, long, long); static void checkOkAddress(u8*, u32, JKRAramBlock*, u32); static void changeGroupIdIfNeed(u8*, int); - static JKRAramBlock* mainRamToAram(u8*, u32, u32, JKRExpandSwitch, u32, JKRHeap*, int, u32*); + static JKRAramBlock* mainRamToAram(u8*, u32, u32, JKRExpandSwitch, u32, JKRHeap*, int); static u8* aramToMainRam(u32, u8*, u32, JKRExpandSwitch, u32, JKRHeap*, int, u32*); static void dump(void); @@ -80,8 +80,8 @@ inline void JKRAramToMainRam(u32 p1, u8* p2, u32 p3, JKRExpandSwitch p4, u32 p5, JKRAram::aramToMainRam(p1, p2, p3, p4, p5, p6, p7, p8); } -inline JKRAramBlock *JKRMainRamToAram(u8 *buf, u32 bufSize, u32 alignedSize, JKRExpandSwitch expandSwitch, u32 fileSize, JKRHeap *heap, int id, u32 *pSize) { - return JKRAram::mainRamToAram(buf, bufSize, alignedSize, expandSwitch, fileSize, heap, id, pSize); +inline JKRAramBlock *JKRMainRamToAram(u8 *buf, u32 bufSize, u32 alignedSize, JKRExpandSwitch expandSwitch, u32 fileSize, JKRHeap *heap, int id) { + return JKRAram::mainRamToAram(buf, bufSize, alignedSize, expandSwitch, fileSize, heap, id); } // void JKRDecompressFromAramToMainRam(u32, void*, u32, u32, u32, u32*); diff --git a/include/JSystem/JKernel/JKRDvdAramRipper.h b/include/JSystem/JKernel/JKRDvdAramRipper.h index 1046e5adf..3561a7e99 100644 --- a/include/JSystem/JKernel/JKRDvdAramRipper.h +++ b/include/JSystem/JKernel/JKRDvdAramRipper.h @@ -35,10 +35,10 @@ public: class JKRDvdFile; class JKRDvdAramRipper { public: - static JKRAramBlock* loadToAram(long, u32, JKRExpandSwitch, u32, u32, u32*); - static JKRAramBlock* loadToAram(JKRDvdFile*, u32, JKRExpandSwitch, u32, u32, u32*); + static JKRAramBlock* loadToAram(long, u32, JKRExpandSwitch, u32, u32); + static JKRAramBlock* loadToAram(JKRDvdFile*, u32, JKRExpandSwitch, u32, u32); static JKRADCommand* loadToAram_Async(JKRDvdFile*, u32, JKRExpandSwitch, void (*)(u32), u32, - u32, u32*); + u32); static JKRADCommand* callCommand_Async(JKRADCommand*); static bool syncAram(JKRADCommand*, int); @@ -49,8 +49,8 @@ public: static u32 sSzpBufferSize; }; -inline JKRAramBlock *JKRDvdToAram(s32 entrynum, u32 p2, JKRExpandSwitch expSwitch, u32 p4, u32 p5, u32 *p6) { - return JKRDvdAramRipper::loadToAram(entrynum, p2, expSwitch, p4, p5, p6); +inline JKRAramBlock *JKRDvdToAram(s32 entrynum, u32 p2, JKRExpandSwitch expSwitch, u32 p4, u32 p5) { + return JKRDvdAramRipper::loadToAram(entrynum, p2, expSwitch, p4, p5); } #endif /* JKRDVDARAMRIPPER_H */ diff --git a/include/JSystem/JKernel/JKRMemArchive.h b/include/JSystem/JKernel/JKRMemArchive.h index eb09c0b20..54fc72459 100644 --- a/include/JSystem/JKernel/JKRMemArchive.h +++ b/include/JSystem/JKernel/JKRMemArchive.h @@ -10,10 +10,13 @@ enum JKRMemBreakFlag { class JKRMemArchive : public JKRArchive { public: + JKRMemArchive(); JKRMemArchive(long, JKRArchive::EMountDirection); - JKRMemArchive(void*, u32, JKRMemBreakFlag); virtual ~JKRMemArchive(); + void fixedInit(s32); + bool mountFixed(void*, JKRMemBreakFlag); + void unmountFixed(); bool open(long, JKRArchive::EMountDirection); bool open(void*, u32, JKRMemBreakFlag); diff --git a/src/JSystem/JKernel/JKRAramArchive.cpp b/src/JSystem/JKernel/JKRAramArchive.cpp index 616dc2fe0..314591d4e 100644 --- a/src/JSystem/JKernel/JKRAramArchive.cpp +++ b/src/JSystem/JKernel/JKRAramArchive.cpp @@ -4,49 +4,310 @@ // #include "JSystem/JKernel/JKRAramArchive.h" -#include "dolphin/types.h" +#include "JSystem/JKernel/JKRAram.h" +#include "JSystem/JKernel/JKRAramBlock.h" +#include "JSystem/JKernel/JKRAramHeap.h" +#include "JSystem/JKernel/JKRDvdFile.h" +#include "JSystem/JKernel/JKRDvdRipper.h" +#include "JSystem/JKernel/JKRDvdAramRipper.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JUtility/JUTAssert.h" +#include "MSL_C/math.h" +#include "MSL_C/string.h" +#include "dolphin/os/OS.h" /* 802B9FE0-802BA088 .text __ct__14JKRAramArchiveFlQ210JKRArchive15EMountDirection */ -JKRAramArchive::JKRAramArchive(long, JKRArchive::EMountDirection) { - /* Nonmatching */ +JKRAramArchive::JKRAramArchive(s32 entryNumber, JKRArchive::EMountDirection mountDirection) : JKRArchive(entryNumber, MOUNT_ARAM) { + mMountDirection = mountDirection; + + if (!this->open(entryNumber)) { + return; + } + + mVolumeType = 'RARC'; + mVolumeName = mStringTable + mNodes->name_offset; + JKRFileLoader::sVolumeList.prepend(&mFileLoaderLink); + mIsMounted = true; } /* 802BA088-802BA1C8 .text __dt__14JKRAramArchiveFv */ JKRAramArchive::~JKRAramArchive() { - /* Nonmatching */ + if (mIsMounted == true) { + if (mArcInfoBlock != NULL) { + SDIFileEntry* entry = mFiles; + for (int i = 0; i < mArcInfoBlock->num_file_entries; entry++, i++) { + if (entry->data != NULL) { + JKRFreeToHeap(mHeap, entry->data); + } + } + + JKRFreeToHeap(mHeap, mArcInfoBlock); + mArcInfoBlock = NULL; + } + + if (mExpandedSize != NULL) { + i_JKRFree(mExpandedSize); + mExpandedSize = NULL; + } + + if (mDvdFile != NULL) { + delete mDvdFile; + } + + if (mBlock != NULL) { + delete mBlock; + } + + JKRFileLoader::sVolumeList.remove(&mFileLoaderLink); + mIsMounted = false; + } +} + +static void dummy() { + OSReport(__FILE__); + OSReport("isMounted()"); + OSReport("Halt"); + OSReport("mMountCount == 1"); } /* 802BA1C8-802BA4EC .text open__14JKRAramArchiveFl */ -void JKRAramArchive::open(long) { - /* Nonmatching */ +bool JKRAramArchive::open(s32 entryNum) { + mArcInfoBlock = NULL; + mNodes = NULL; + mFiles = NULL; + mStringTable = NULL; + mBlock = NULL; + + mDvdFile = new (JKRGetSystemHeap(), mMountDirection == MOUNT_DIRECTION_HEAD ? 4 : -4) JKRDvdFile(entryNum); + if (mDvdFile == NULL) { + mMountMode = 0; + return 0; + } + + // NOTE: a different struct is used here for sure, unfortunately i can't get any hits on this address, so gonna leave it like this for now + SArcHeader *mem = (SArcHeader *)JKRAllocFromSysHeap(32, -32); + if (mem == NULL) { + mMountMode = 0; + } else { + JKRDvdToMainRam(entryNum, (u8 *)mem, EXPAND_SWITCH_UNKNOWN1, 32, NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, &mCompression); + int alignment = mMountDirection == MOUNT_DIRECTION_HEAD ? 32 : -32; + u32 alignedSize = ALIGN_NEXT(mem->file_data_offset, 32); + mArcInfoBlock = (SArcDataInfo *)JKRAllocFromHeap(mHeap, alignedSize, alignment); + if (mArcInfoBlock == NULL) { + mMountMode = 0; + } else { + JKRDvdToMainRam(entryNum, (u8 *)mArcInfoBlock, EXPAND_SWITCH_UNKNOWN1, alignedSize, NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 32, NULL); + + mNodes = (SDIDirEntry *)((u8 *)mArcInfoBlock + mArcInfoBlock->node_offset); + mFiles = (SDIFileEntry *)((u8 *)mArcInfoBlock + mArcInfoBlock->file_entry_offset); + mStringTable = (char *)((u8 *)mArcInfoBlock + mArcInfoBlock->string_table_offset); + mExpandedSize = NULL; + + u8 compressedFiles = 0; // maybe a check for if the last file is compressed? + + SDIFileEntry *fileEntry = mFiles; + for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) { + u8 flag = fileEntry->type_flags_and_name_offset >> 24; + if ((flag & 1)) + { + compressedFiles |= (flag & JKRARCHIVE_ATTR_COMPRESSION); + } + fileEntry++; + } + + if (compressedFiles != 0) { + mExpandedSize = (s32 *)JKRAllocFromHeap(mHeap, mArcInfoBlock->num_file_entries << 2, abs(alignment)); + if (mExpandedSize == NULL) { + i_JKRFree(mArcInfoBlock); + mMountMode = 0; + goto cleanup; + } + memset(mExpandedSize, 0, mArcInfoBlock->num_file_entries << 2); + } + + u32 aramSize = ALIGN_NEXT(mem->file_data_length, 32); + mBlock = (JKRAramBlock*) JKRAllocFromAram(aramSize, mMountDirection == MOUNT_DIRECTION_HEAD ? JKRAramHeap::HEAD : JKRAramHeap::TAIL); + if(mBlock == NULL) { + if (mArcInfoBlock) { + i_JKRFree(mArcInfoBlock); + } + if(mExpandedSize) { + i_JKRFree(mExpandedSize); + } + mMountMode = 0; + } + else { + JKRDvdToAram(entryNum, mBlock->getAddress(), EXPAND_SWITCH_UNKNOWN1, mem->header_length + mem->file_data_offset, 0); + } + } + } +cleanup: + if (mem != NULL) { + JKRFreeToSysHeap(mem); + } + if (mMountMode == 0) { + OSReport(":::[%s: %d] Cannot alloc memory\n", __FILE__, 400); + if (mDvdFile != NULL) { + delete mDvdFile; + } + return false; + } + return true; } /* 802BA4EC-802BA640 .text fetchResource__14JKRAramArchiveFPQ210JKRArchive12SDIFileEntryPUl */ -void JKRAramArchive::fetchResource(JKRArchive::SDIFileEntry*, unsigned long*) { - /* Nonmatching */ +void* JKRAramArchive::fetchResource(SDIFileEntry* pEntry, u32* pOutSize) { + JUT_ASSERT(427, isMounted()); + u32 outSize; + u8* outBuf; + if (pOutSize == NULL) { + pOutSize = &outSize; + } + + JKRCompression compression = JKRConvertAttrToCompressionType(pEntry->getFlags()); + if (pEntry->data == NULL) { + u32 size = JKRAramArchive::fetchResource_subroutine( + pEntry->data_offset + mBlock->getAddress(), pEntry->data_size, mHeap, compression, + &outBuf); + + *pOutSize = size; + if (size == NULL) { + return NULL; + } + + pEntry->data = outBuf; + if (compression == COMPRESSION_YAZ0) { + this->setExpandSize(pEntry, *pOutSize); + } + } else { + if (compression == COMPRESSION_YAZ0) { + *pOutSize = this->getExpandSize(pEntry); + } else { + *pOutSize = pEntry->data_size; + } + } + + return pEntry->data; } /* 802BA640-802BA788 .text fetchResource__14JKRAramArchiveFPvUlPQ210JKRArchive12SDIFileEntryPUl */ -void JKRAramArchive::fetchResource(void*, unsigned long, JKRArchive::SDIFileEntry*, unsigned long*) { +void* JKRAramArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* pEntry, u32* resourceSize) { /* Nonmatching */ + JUT_ASSERT(500, isMounted()); + u32 size = pEntry->data_size; + if (size > bufferSize) { + size = bufferSize; + } + JKRCompression compression = JKRConvertAttrToCompressionType(pEntry->getFlags()); + if (pEntry->data == NULL) { + // can't get it to store the result in r28 + bufferSize &= ~(0x20 - 1); + size = JKRAramArchive::fetchResource_subroutine(pEntry->data_offset + mBlock->getAddress(), + size, (u8*)buffer, bufferSize, compression); + } else { + if (compression == COMPRESSION_YAZ0) { + u32 expandSize = this->getExpandSize(pEntry); + if (expandSize != NULL) { + size = expandSize; + } + } + if (size > bufferSize) { + size = bufferSize; + } + JKRHeap::copyMemory(buffer, pEntry->data, size); + } + if (resourceSize != NULL) { + *resourceSize = size; + } + return buffer; } /* 802BA788-802BA894 .text fetchResource_subroutine__14JKRAramArchiveFUlUlPUcUli */ -void JKRAramArchive::fetchResource_subroutine(unsigned long, unsigned long, unsigned char*, unsigned long, int) { - /* Nonmatching */ +u32 JKRAramArchive::fetchResource_subroutine(u32 srcAram, u32 srcLength, u8* dst, u32 dstLength, int compression) { + JUT_ASSERT(613, ( srcAram & 0x1f ) == 0); + u32 outLen; + u32 srcSize = ALIGN_NEXT(srcLength, 0x20); + u32 dstSize = ALIGN_PREV(dstLength, 0x20); + + switch (compression) { + case COMPRESSION_NONE: + if (srcSize > dstSize) { + srcSize = dstSize; + } + JKRAramToMainRam(srcAram, dst, srcSize, EXPAND_SWITCH_UNKNOWN0, dstSize, NULL, -1, &outLen); + return outLen; + case COMPRESSION_YAY0: + case COMPRESSION_YAZ0: + JKRAramToMainRam(srcAram, dst, srcSize, EXPAND_SWITCH_UNKNOWN1, dstSize, NULL, -1, &outLen); + return outLen; + default: + OSPanic(__FILE__, 640, ":::??? bad sequence\n"); + return 0; + } } /* 802BA894-802BAA48 .text fetchResource_subroutine__14JKRAramArchiveFUlUlP7JKRHeapiPPUc */ -void JKRAramArchive::fetchResource_subroutine(unsigned long, unsigned long, JKRHeap*, int, unsigned char**) { +u32 JKRAramArchive::fetchResource_subroutine(u32 entryNum, u32 length, JKRHeap* pHeap, int compression, u8** out) { /* Nonmatching */ + u32 readLen; + u32 alignedLen = ALIGN_NEXT(length, 0x20); + + u8* buffer; + switch (compression) { + case COMPRESSION_NONE: + buffer = static_cast(JKRAllocFromHeap(pHeap, alignedLen, 0x20)); + JUT_ASSERT(662, buffer != 0); + JKRAramToMainRam(entryNum, buffer, alignedLen, EXPAND_SWITCH_UNKNOWN0, alignedLen, + NULL, -1, NULL); + *out = buffer; + return length; + case COMPRESSION_YAY0: + case COMPRESSION_YAZ0: + u8 tmpBuf[0x40]; + u8* buf = (u8*)ALIGN_PREV((s32)&tmpBuf[0x1F], sizeof(SArcHeader)); + JKRAramToMainRam(entryNum, buf, sizeof(SArcHeader), EXPAND_SWITCH_UNKNOWN0, 0, NULL, -1, NULL); + length = ALIGN_NEXT(JKRDecompExpandSize(buf), sizeof(SArcHeader)); + buffer = static_cast(JKRAllocFromHeap(pHeap, length, sizeof(SArcHeader))); + JUT_ASSERT(688, buffer); + JKRAramToMainRam(entryNum, buffer, alignedLen, EXPAND_SWITCH_UNKNOWN1, length, pHeap, + -1, &readLen); + *out = buffer; + return readLen; + default: + OSPanic(__FILE__, 698, ":::??? bad sequence\n"); + return 0; + } } /* 802BAA48-802BAB74 .text getExpandedResSize__14JKRAramArchiveCFPCv */ -void JKRAramArchive::getExpandedResSize(const void*) const { - /* Nonmatching */ +u32 JKRAramArchive::getExpandedResSize(const void* ptr) const { + if (mExpandedSize == NULL) { + return this->getResSize(ptr); + } + + JKRArchive::SDIFileEntry* entry = this->findPtrResource(ptr); + if (entry == NULL) { + return 0xFFFFFFFF; + } + + if (entry->getCompressFlag() == 0) { + return this->getResSize(ptr); + } + + u32 expandSize = this->getExpandSize(entry); + if (expandSize != 0) { + return expandSize; + } + + u8 tmpBuf[0x40]; + u8* buf = (u8*)ALIGN_PREV((s32)&tmpBuf[0x1F], 0x20); + JKRAramToMainRam(entry->data_offset + mBlock->getAddress(), buf, 0x20, + EXPAND_SWITCH_UNKNOWN0, 0, NULL, -1, NULL); + expandSize = JKRDecompExpandSize(buf); + // ??? casting away const? + ((JKRArchive*)this)->setExpandSize(entry, expandSize); + return expandSize; } /* 802BAB74-802BABD4 .text __dt__7JKRFileFv */ -JKRFile::~JKRFile() { - /* Nonmatching */ -} +//JKRFile::~JKRFile() {} diff --git a/src/JSystem/JKernel/JKRCompArchive.cpp b/src/JSystem/JKernel/JKRCompArchive.cpp index 925fa80af..a7a06f47a 100644 --- a/src/JSystem/JKernel/JKRCompArchive.cpp +++ b/src/JSystem/JKernel/JKRCompArchive.cpp @@ -4,44 +4,392 @@ // #include "JSystem/JKernel/JKRCompArchive.h" -#include "dolphin/types.h" +#include "JSystem/JKernel/JKRAram.h" +#include "JSystem/JKernel/JKRAramArchive.h" +#include "JSystem/JKernel/JKRAramBlock.h" +#include "JSystem/JKernel/JKRDecomp.h" +#include "JSystem/JKernel/JKRDvdAramRipper.h" +#include "JSystem/JKernel/JKRDvdArchive.h" +#include "JSystem/JKernel/JKRDvdFile.h" +#include "JSystem/JKernel/JKRDvdRipper.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JKernel/JKRMemArchive.h" +#include "JSystem/JUtility/JUTAssert.h" +#include "MSL_C/math.h" +#include "MSL_C/string.h" +#include "dolphin/os/OS.h" /* 802BB82C-802BB8D4 .text __ct__14JKRCompArchiveFlQ210JKRArchive15EMountDirection */ -JKRCompArchive::JKRCompArchive(long, JKRArchive::EMountDirection) { - /* Nonmatching */ +JKRCompArchive::JKRCompArchive(s32 entryNum, JKRArchive::EMountDirection mountDirection) : JKRArchive(entryNum, MOUNT_COMP) { + mMountDirection = mountDirection; + + if (!open(entryNum)) { + return; + } + + mVolumeType = 'RARC'; + mVolumeName = &mStringTable[mNodes->name_offset]; + sVolumeList.prepend(&mFileLoaderLink); + mIsMounted = true; } /* 802BB8D4-802BBA14 .text __dt__14JKRCompArchiveFv */ JKRCompArchive::~JKRCompArchive() { - /* Nonmatching */ + if (mArcInfoBlock != NULL) { + SDIFileEntry* file = mFiles; + for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) { + if (!((file->type_flags_and_name_offset >> 0x18) & 0x10) && file->data != NULL) { + JKRFreeToHeap(mHeap, file->data); + } + + file++; + } + + JKRFreeToHeap(mHeap, mArcInfoBlock); + mArcInfoBlock = NULL; + } + + if (mAramPart != NULL) { + delete mAramPart; + } + + if (mExpandedSize != NULL) { + i_JKRFree(mExpandedSize); + mExpandedSize = NULL; + } + + if (mDvdFile != NULL) { + delete mDvdFile; + } + + sVolumeList.remove(&mFileLoaderLink); + mIsMounted = false; +} + +static void dummy() { + OSReport(__FILE__); + OSReport("isMounted()"); + OSReport("Halt"); + OSReport("mMountCount == 1"); } /* 802BBA14-802BBFDC .text open__14JKRCompArchiveFl */ -void JKRCompArchive::open(long) { - /* Nonmatching */ +bool JKRCompArchive::open(s32 entryNum) { + mArcInfoBlock = NULL; + field_0x64 = 0; + mAramPart = NULL; + field_0x6c = 0; + mSizeOfMemPart = 0; + mSizeOfAramPart = 0; + field_0x7c = 0; + mNodes = NULL; + mFiles = NULL; + mStringTable = NULL; + + mDvdFile = new (JKRGetSystemHeap(), 0) JKRDvdFile(entryNum); + if(mDvdFile == NULL) { + mMountMode = 0; + return 0; + } + SArcHeader *arcHeader = (SArcHeader *)JKRAllocFromSysHeap(sizeof(SArcHeader), -32); // NOTE: unconfirmed if this struct is used + if(arcHeader == NULL) { + mMountMode = 0; + } + else { + int alignment; + + JKRDvdToMainRam(entryNum, (u8 *)arcHeader, EXPAND_SWITCH_UNKNOWN1, 32, NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, &mCompression); + + mSizeOfMemPart = arcHeader->field_0x14; + mSizeOfAramPart = arcHeader->field_0x18; + JUT_ASSERT(346, ( mSizeOfMemPart & 0x1f ) == 0); + JUT_ASSERT(347, ( mSizeOfAramPart & 0x1f ) == 0); + + switch (mCompression) + { + case COMPRESSION_NONE: + case COMPRESSION_YAZ0: + alignment = mMountDirection == 1 ? 32 : -32; + mArcInfoBlock = (SArcDataInfo *)JKRAllocFromHeap(mHeap, arcHeader->file_data_offset + mSizeOfMemPart, alignment); + if (mArcInfoBlock == NULL) { + mMountMode = 0; + } + else + { + JKRDvdToMainRam(entryNum, (u8 *)mArcInfoBlock, EXPAND_SWITCH_UNKNOWN1, (u32)arcHeader->file_data_offset + mSizeOfMemPart, + NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0x20, NULL); + field_0x64 = (u32)mArcInfoBlock + arcHeader->file_data_offset; + + if (mSizeOfAramPart != 0) { + mAramPart = (JKRAramBlock*)JKRAllocFromAram(mSizeOfAramPart, JKRAramHeap::HEAD); + if(mAramPart == NULL) { + mMountMode = 0; + break; + } + + JKRDvdToAram(entryNum, mAramPart->getAddress(), EXPAND_SWITCH_UNKNOWN1, arcHeader->header_length + arcHeader->file_data_offset + mSizeOfMemPart, 0); + } + + mNodes = (SDIDirEntry*)((u32)mArcInfoBlock + mArcInfoBlock->node_offset); + mFiles = (SDIFileEntry *)((u32)mArcInfoBlock + mArcInfoBlock->file_entry_offset); + mStringTable = (char*)((u32)mArcInfoBlock + mArcInfoBlock->string_table_offset); + field_0x6c = arcHeader->header_length + arcHeader->file_data_offset; + } + break; + + case COMPRESSION_YAY0: + u32 alignedSize = ALIGN_NEXT(mDvdFile->getFileSize(), 32); + alignment = ((mMountDirection == 1) ? 32 : -32); + u8 *buf = (u8 *)JKRAllocFromSysHeap(alignedSize, -alignment); + + if(buf == NULL) { + mMountMode = 0; + } + else { + JKRDvdToMainRam(entryNum, buf, EXPAND_SWITCH_UNKNOWN2, alignedSize, NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, NULL); + u32 expandSize = ALIGN_NEXT(JKRDecompExpandSize(buf), 32); + u8 *mem = (u8 *)JKRAllocFromHeap(mHeap, expandSize, -alignment); + + if(mem == NULL) { + mMountMode = 0; + } + else { + arcHeader = (SArcHeader *)mem; + JKRDecompress((u8 *)buf, (u8 *)mem, expandSize, 0); + JKRFreeToSysHeap(buf); + + mArcInfoBlock = (SArcDataInfo *)JKRAllocFromHeap(mHeap, arcHeader->file_data_offset + mSizeOfMemPart, alignment); + if(mArcInfoBlock == NULL) { + mMountMode = 0; + } + else { + // arcHeader + 1 should lead to 0x20, which is the data after the header + JKRHeap::copyMemory((u8 *)mArcInfoBlock, arcHeader + 1, (arcHeader->file_data_offset + mSizeOfMemPart)); + field_0x64 = (u32)mArcInfoBlock + arcHeader->file_data_offset; + if (mSizeOfAramPart != 0) { + mAramPart = (JKRAramBlock*)JKRAllocFromAram(mSizeOfAramPart, JKRAramHeap::HEAD); + if(mAramPart == NULL) { + mMountMode = 0; + } + else { + JKRMainRamToAram((u8 *)mem + arcHeader->header_length + arcHeader->file_data_offset + mSizeOfMemPart, + mAramPart->getAddress(), mSizeOfAramPart, EXPAND_SWITCH_UNKNOWN0, 0, NULL, -1); + } + } + } + } + } + mNodes = (SDIDirEntry *)((u32)mArcInfoBlock + mArcInfoBlock->node_offset); + mFiles = (SDIFileEntry *)((u32)mArcInfoBlock + mArcInfoBlock->file_entry_offset); + mStringTable = (char *)((u32)mArcInfoBlock + mArcInfoBlock->string_table_offset); + field_0x6c = arcHeader->header_length + arcHeader->file_data_offset; + break; + } + mExpandedSize = NULL; + u8 compressedFiles = 0; + SDIFileEntry *fileEntry = mFiles; + for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) + { + u8 flag = fileEntry->type_flags_and_name_offset >> 0x18; + if (((flag & 0x1) != 0) && (((flag)&0x10) == 0)) + { + compressedFiles = compressedFiles | (flag & 4); + } + fileEntry++; + } + + if (compressedFiles != 0) + { + mExpandedSize = (s32 *)JKRAllocFromHeap(mHeap, mArcInfoBlock->num_file_entries * 4, abs(alignment)); + if (mExpandedSize == NULL) + { + JKRFreeToSysHeap(mArcInfoBlock); + mMountMode = 0; + } + else + { + memset(mExpandedSize, 0, mArcInfoBlock->num_file_entries * 4); + } + } + } + + if (arcHeader != NULL) + { + JKRFreeToSysHeap(arcHeader); + } + if(mMountMode == 0) { + OSReport(":::[%s: %d] Cannot alloc memory in mounting CompArchive\n", __FILE__, 548); + if(mDvdFile != NULL) { + delete mDvdFile; + } + return false; + } + return true; } /* 802BBFDC-802BC198 .text fetchResource__14JKRCompArchiveFPQ210JKRArchive12SDIFileEntryPUl */ -void JKRCompArchive::fetchResource(JKRArchive::SDIFileEntry*, unsigned long*) { - /* Nonmatching */ +void* JKRCompArchive::fetchResource(SDIFileEntry* fileEntry, u32* pSize) { + JUT_ASSERT(578, isMounted()); + u32 ptrSize; + u32 size = fileEntry->data_size; + int compression = JKRConvertAttrToCompressionType(fileEntry->type_flags_and_name_offset >> 0x18); + + if(pSize == NULL) { + pSize = &ptrSize; // this makes barely any sense but ok + } + + if (fileEntry->data == NULL) { + u32 flag = fileEntry->type_flags_and_name_offset >> 0x18; + if(flag & 0x10) { + fileEntry->data = (void *)(field_0x64 + fileEntry->data_offset); + *pSize = size; + } + else if (flag & 0x20) { + u8 *data; + *pSize = JKRAramArchive::fetchResource_subroutine(fileEntry->data_offset + mAramPart->getAddress() - mSizeOfMemPart, size, mHeap, compression, &data); + fileEntry->data = data; + if(compression == COMPRESSION_YAZ0) { + setExpandSize(fileEntry, *pSize); + } + } + else if (flag & 0x40) { + u8 *data; + u32 resSize = JKRDvdArchive::fetchResource_subroutine(mEntryNum, field_0x6c + fileEntry->data_offset, fileEntry->data_size, mHeap, compression, mCompression, &data); + if (pSize != NULL) { + *pSize = resSize; + } + fileEntry->data = data; + if (compression == COMPRESSION_YAZ0) { + setExpandSize(fileEntry, *pSize); + } + } + } + else { + if (pSize != NULL) { + *pSize = fileEntry->data_size; + } + } + return fileEntry->data; } /* 802BC198-802BC370 .text fetchResource__14JKRCompArchiveFPvUlPQ210JKRArchive12SDIFileEntryPUl */ -void JKRCompArchive::fetchResource(void*, unsigned long, JKRArchive::SDIFileEntry*, unsigned long*) { - /* Nonmatching */ +void* JKRCompArchive::fetchResource(void* data, u32 compressedSize, SDIFileEntry *fileEntry, u32 *pSize) { + u32 size = 0; + JUT_ASSERT(696, isMounted()); + u32 fileSize = fileEntry->data_size; + u32 alignedSize = ALIGN_NEXT(fileSize, 32); + u32 fileFlag = fileEntry->type_flags_and_name_offset >> 0x18; + int compression = JKRConvertAttrToCompressionType(fileFlag); + + if(fileEntry->data != NULL) { + if (compression == COMPRESSION_YAZ0) { + u32 expandSize = getExpandSize(fileEntry); + if (expandSize != 0) { + fileSize = expandSize; + } + } + + if (fileSize > compressedSize) { + fileSize = compressedSize; + } + + JKRHeap::copyMemory(data, fileEntry->data, fileSize); + size = fileSize; + } + else { + if (fileFlag & 0x10) { + size = JKRMemArchive::fetchResource_subroutine((u8 *)(field_0x64 + fileEntry->data_offset), alignedSize, (u8 *)data, + compressedSize & ~31, compression); + } + else if (fileFlag & 0x20) { + size = JKRAramArchive::fetchResource_subroutine(fileEntry->data_offset + mAramPart->getAddress() - mSizeOfMemPart, + alignedSize, (u8 *)data, compressedSize & ~31, compression); + } + else if (fileFlag & 0x40){ + size = JKRDvdArchive::fetchResource_subroutine(mEntryNum, field_0x6c + fileEntry->data_offset, alignedSize, (u8 *)data, + compressedSize & ~31, compression, mCompression); + } else { + OSPanic(__FILE__, 756, ":::CompArchive: bad mode."); + } + } + + if(pSize != NULL) { + *pSize = size; + } + return data; } /* 802BC370-802BC404 .text removeResourceAll__14JKRCompArchiveFv */ void JKRCompArchive::removeResourceAll() { - /* Nonmatching */ + if (mArcInfoBlock != NULL && mMountMode != MOUNT_MEM) { + SDIFileEntry* fileEntry = mFiles; + for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) { + int tmp = fileEntry->type_flags_and_name_offset >> 0x18; + + if (fileEntry->data != NULL) { + if (!(tmp & 0x10)) { + JKRFreeToHeap(mHeap, fileEntry->data); + } + + fileEntry->data = NULL; + } + } + } } /* 802BC404-802BC470 .text removeResource__14JKRCompArchiveFPv */ -void JKRCompArchive::removeResource(void*) { - /* Nonmatching */ +bool JKRCompArchive::removeResource(void* resource) { + SDIFileEntry* fileEntry = findPtrResource(resource); + if (!fileEntry) + return false; + + if (!((fileEntry->type_flags_and_name_offset >> 0x18) & 0x10)) { + JKRFreeToHeap(mHeap, resource); + } + + fileEntry->data = NULL; + return true; } /* 802BC470-802BC610 .text getExpandedResSize__14JKRCompArchiveCFPCv */ -void JKRCompArchive::getExpandedResSize(const void*) const { - /* Nonmatching */ +u32 JKRCompArchive::getExpandedResSize(const void* resource) const { + if (mExpandedSize == NULL) { + return getResSize(resource); + } + + SDIFileEntry *fileEntry = findPtrResource(resource); + if(!fileEntry) { + return 0xffffffff; + } + + u8 flags = (fileEntry->type_flags_and_name_offset >> 0x18); + if((flags & 4) == 0) { // not compressed + return getResSize(resource); + } + + if ((flags & 0x10) != 0) { + return JKRDecompExpandSize((u8 *)resource); + } + + u8 buf[64]; + u8 *bufPtr = (u8 *)ALIGN_NEXT((u32)buf, 32); + if ((flags & 0x20) != 0) { + u32 addr = mAramPart->mAddress; + addr = fileEntry->data_offset + addr; + JKRAramToMainRam(addr, bufPtr, sizeof(buf) / 2, EXPAND_SWITCH_UNKNOWN0, 0, NULL, -1, NULL); + } + else if ((flags & 0x40) != 0) { + JKRDvdToMainRam(mEntryNum, bufPtr, EXPAND_SWITCH_UNKNOWN2, sizeof(buf) / 2, NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, field_0x6c + fileEntry->data_offset, NULL); + DCInvalidateRange(bufPtr, sizeof(buf) / 2); + } + else { +#if VERSION == VERSION_JPN + OSPanic(__FILE__, 948, "illegal resource."); +#else + OSPanic(__FILE__, 944, "illegal resource."); +#endif + } + u32 expandSize = JKRDecompExpandSize(bufPtr); + const_cast(this)->setExpandSize(fileEntry, expandSize); + return expandSize; } diff --git a/src/JSystem/JKernel/JKRDvdArchive.cpp b/src/JSystem/JKernel/JKRDvdArchive.cpp index bd776c69a..7ec088dba 100644 --- a/src/JSystem/JKernel/JKRDvdArchive.cpp +++ b/src/JSystem/JKernel/JKRDvdArchive.cpp @@ -4,44 +4,367 @@ // #include "JSystem/JKernel/JKRDvdArchive.h" -#include "dolphin/types.h" +#include "JSystem/JKernel/JKRDvdFile.h" +#include "JSystem/JKernel/JKRDvdRipper.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JUtility/JUTAssert.h" +#include "MSL_C/math.h" +#include "MSL_C/string.h" +#include "dolphin/os/OS.h" /* 802BABD4-802BAC7C .text __ct__13JKRDvdArchiveFlQ210JKRArchive15EMountDirection */ -JKRDvdArchive::JKRDvdArchive(long, JKRArchive::EMountDirection) { - /* Nonmatching */ +JKRDvdArchive::JKRDvdArchive(s32 entryNum, JKRArchive::EMountDirection mountDirection) : JKRArchive(entryNum, MOUNT_DVD) { + mMountDirection = mountDirection; + if (!open(entryNum)) + return; + + mVolumeType = 'RARC'; + mVolumeName = mStringTable + mNodes->name_offset; + getVolumeList().prepend(&mFileLoaderLink); + mIsMounted = true; } /* 802BAC7C-802BAD98 .text __dt__13JKRDvdArchiveFv */ JKRDvdArchive::~JKRDvdArchive() { - /* Nonmatching */ + if (mIsMounted == true) { + if (mArcInfoBlock) { + SDIFileEntry* fileEntry = mFiles; + int i = 0; + for (; i < mArcInfoBlock->num_file_entries; fileEntry++, i++) { + if (fileEntry->data) { + JKRFreeToHeap(mHeap, fileEntry->data); + } + } + + JKRFreeToHeap(mHeap, mArcInfoBlock); + mArcInfoBlock = NULL; + } + + if (mExpandedSize) { + i_JKRFree(mExpandedSize); + mExpandedSize = NULL; + } + + if (mDvdFile) { + delete mDvdFile; + } + + getVolumeList().remove(&mFileLoaderLink); + mIsMounted = false; + } +} + +static void dummy() { + OSReport(__FILE__); + OSReport("isMounted()"); + OSReport("Halt"); + OSReport("mMountCount == 1"); } /* 802BAD98-802BB024 .text open__13JKRDvdArchiveFl */ -void JKRDvdArchive::open(long) { - /* Nonmatching */ +bool JKRDvdArchive::open(s32 entryNum) { + mArcInfoBlock = NULL; + field_0x64 = NULL; + mNodes = NULL; + mFiles = NULL; + mStringTable = NULL; + + mDvdFile = new (JKRGetSystemHeap(), 0) JKRDvdFile(entryNum); + if (!mDvdFile) { + mMountMode = UNKNOWN_MOUNT_MODE; + return false; + } + + SArcHeader* arcHeader = (SArcHeader*)JKRAllocFromSysHeap(sizeof(SArcHeader), 0x20); + if (!arcHeader) { + mMountMode = UNKNOWN_MOUNT_MODE; + goto cleanup; + } + + JKRDvdToMainRam(entryNum, (u8*)arcHeader, EXPAND_SWITCH_UNKNOWN1, sizeof(SArcHeader), NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, &mCompression); + + int alignment = mMountDirection == MOUNT_DIRECTION_HEAD ? 0x20 : -0x20; + + mArcInfoBlock = (SArcDataInfo*)JKRAllocFromHeap(mHeap, arcHeader->file_data_offset, alignment); + if (!mArcInfoBlock) { + mMountMode = UNKNOWN_MOUNT_MODE; + goto cleanup; + } + + JKRDvdToMainRam(entryNum, (u8*)mArcInfoBlock, EXPAND_SWITCH_UNKNOWN1, + arcHeader->file_data_offset, NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, + sizeof(SArcHeader), NULL); + + mNodes = (SDIDirEntry*)((int)&mArcInfoBlock->num_nodes + mArcInfoBlock->node_offset); + mFiles = (SDIFileEntry*)((int)&mArcInfoBlock->num_nodes + mArcInfoBlock->file_entry_offset); + mStringTable = (char*)((int)&mArcInfoBlock->num_nodes + mArcInfoBlock->string_table_offset); + mExpandedSize = NULL; + + u8 useCompression = 0; + SDIFileEntry* fileEntry = mFiles; + for (u32 i = 0; i < mArcInfoBlock->num_file_entries; fileEntry++, i++) { + if (fileEntry->isUnknownFlag1()) { + useCompression |= fileEntry->getCompressFlag(); + } + } + + if (useCompression) { + mExpandedSize = (s32*)JKRAllocFromHeap(mHeap, sizeof(s32) * mArcInfoBlock->num_file_entries, + abs(alignment)); + if (!mExpandedSize) { + // !@bug: mArcInfoBlock is allocated from mHeap but free'd to sSystemHeap. I don't know + // what will happen if mHeap != sSystemHeap, but it's still a bug to free to the wrong + // allocator. + JKRFreeToSysHeap(mArcInfoBlock); + mMountMode = UNKNOWN_MOUNT_MODE; + goto cleanup; + } + + memset(mExpandedSize, 0, sizeof(s32) * mArcInfoBlock->num_file_entries); + } + + field_0x64 = arcHeader->header_length + arcHeader->file_data_offset; + +cleanup: + if (arcHeader) { + JKRFreeToSysHeap(arcHeader); + } + + if (mMountMode == UNKNOWN_MOUNT_MODE) { + OSReport(":::Cannot alloc memory [%s][%d]\n", __FILE__, 382); + if (mDvdFile) { + delete mDvdFile; + } + return false; + } + + return true; } /* 802BB024-802BB17C .text fetchResource__13JKRDvdArchiveFPQ210JKRArchive12SDIFileEntryPUl */ -void JKRDvdArchive::fetchResource(JKRArchive::SDIFileEntry*, unsigned long*) { - /* Nonmatching */ +void* JKRDvdArchive::fetchResource(SDIFileEntry* fileEntry, u32* returnSize) { + JUT_ASSERT(413, isMounted()); + u32 tempReturnSize; + if (returnSize == NULL) { + returnSize = &tempReturnSize; + } + + JKRCompression fileCompression = JKRConvertAttrToCompressionType(fileEntry->getAttr()); + if (!fileEntry->data) { + u8* resourcePtr; + u32 resourceSize = fetchResource_subroutine( + mEntryNum, this->field_0x64 + fileEntry->data_offset, fileEntry->data_size, mHeap, + fileCompression, mCompression, &resourcePtr); + *returnSize = resourceSize; + if (resourceSize == 0) { + return NULL; + } + + fileEntry->data = resourcePtr; + if (fileCompression == COMPRESSION_YAZ0) { + setExpandSize(fileEntry, *returnSize); + } + } else { + if (fileCompression == COMPRESSION_YAZ0) { + u32 resourceSize = getExpandSize(fileEntry); + *returnSize = resourceSize; + } else { + *returnSize = fileEntry->data_size; + } + } + + return fileEntry->data; } /* 802BB17C-802BB2BC .text fetchResource__13JKRDvdArchiveFPvUlPQ210JKRArchive12SDIFileEntryPUl */ -void JKRDvdArchive::fetchResource(void*, unsigned long, JKRArchive::SDIFileEntry*, unsigned long*) { +void* JKRDvdArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* fileEntry, u32* returnSize) { /* Nonmatching */ + JUT_ASSERT(489, isMounted()); + u32 otherSize; + u32 size = fileEntry->data_size; + JKRCompression fileCompression = JKRConvertAttrToCompressionType(fileEntry->getAttr()); + + if (!fileEntry->data) { + bufferSize = ALIGN_PREV(bufferSize, 0x20); + size = fetchResource_subroutine(mEntryNum, field_0x64 + fileEntry->data_offset, + fileEntry->data_size, (u8*)buffer, bufferSize, fileCompression, + mCompression); + } else { + if (fileCompression == COMPRESSION_YAZ0) { + otherSize = getExpandSize(fileEntry); + if (otherSize) { + size = otherSize; + } + } + + if (size > bufferSize) { + size = bufferSize; + } + + JKRHeap::copyMemory(buffer, fileEntry->data, size); + } + + if (returnSize) { + *returnSize = size; + } + return buffer; } /* 802BB2BC-802BB47C .text fetchResource_subroutine__13JKRDvdArchiveFlUlUlPUcUlii */ -void JKRDvdArchive::fetchResource_subroutine(long, unsigned long, unsigned long, unsigned char*, unsigned long, int, int) { - /* Nonmatching */ +u32 JKRDvdArchive::fetchResource_subroutine(s32 entryNum, u32 offset, u32 size, u8* dst, u32 dstLength, int fileCompression, int archiveCompression) { + u32 alignedSize = ALIGN_NEXT(size, 0x20); + u32 alignedDstLength = ALIGN_PREV(dstLength, 0x20); + + switch (archiveCompression) { + case COMPRESSION_NONE: { + switch (fileCompression) { + case COMPRESSION_NONE: + if (alignedSize > alignedDstLength) { + alignedSize = alignedDstLength; + } + + JKRDvdToMainRam(entryNum, dst, EXPAND_SWITCH_UNKNOWN0, alignedSize, NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + return alignedSize; + case COMPRESSION_YAY0: + case COMPRESSION_YAZ0: + // The dst pointer to JKRDvdToMainRam should be aligned to 32 bytes. This will align + // arcHeader to 32 bytes on the stack. + char arcHeaderBuffer[64]; + u8* arcHeader = (u8*)ALIGN_NEXT((u32)arcHeaderBuffer, 0x20); + JKRDvdToMainRam(entryNum, arcHeader, EXPAND_SWITCH_UNKNOWN2, sizeof(SArcHeader), + NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + DCInvalidateRange(arcHeader, sizeof(SArcHeader)); + + u32 decompressedSize = JKRDecompExpandSize(arcHeader); + u32 alignedDecompressedSize = ALIGN_NEXT(decompressedSize, 0x20); + if (alignedDecompressedSize > alignedDstLength) { + alignedDecompressedSize = alignedDstLength; + } + + JKRDvdToMainRam(entryNum, dst, EXPAND_SWITCH_UNKNOWN1, alignedDecompressedSize, NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + return decompressedSize; + } + } + + case COMPRESSION_YAZ0: { + if (size > alignedDstLength) { + size = alignedDstLength; + } + + JKRDvdToMainRam(entryNum, dst, EXPAND_SWITCH_UNKNOWN1, size, NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + return size; + } + + case COMPRESSION_YAY0: { + OSPanic(__FILE__, 603, "Sorry, not prepared for SZP archive.\n"); + return 0; + } + + default: { + OSPanic(__FILE__, 609, ":::??? bad sequence\n"); + return 0; + } + } } /* 802BB47C-802BB6F8 .text fetchResource_subroutine__13JKRDvdArchiveFlUlUlP7JKRHeapiiPPUc */ -void JKRDvdArchive::fetchResource_subroutine(long, unsigned long, unsigned long, JKRHeap*, int, int, unsigned char**) { - /* Nonmatching */ +u32 JKRDvdArchive::fetchResource_subroutine(s32 entryNum, u32 offset, u32 size, JKRHeap* heap, int fileCompression, int archiveCompression, u8** returnResource) { + u32 alignedSize = ALIGN_NEXT(size, 0x20); + u8* buffer; + + switch (archiveCompression) { + case COMPRESSION_NONE: { + switch (fileCompression) { + case COMPRESSION_NONE: + buffer = (u8*)JKRAllocFromHeap(heap, alignedSize, sizeof(SArcHeader)); + JUT_ASSERT(631, buffer != 0); + + JKRDvdToMainRam(entryNum, buffer, EXPAND_SWITCH_UNKNOWN0, alignedSize, NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + + *returnResource = buffer; + return alignedSize; + case COMPRESSION_YAY0: + case COMPRESSION_YAZ0: + // The dst pointer to JKRDvdToMainRam should be aligned to 32 bytes. This will align + // arcHeader to 32 bytes on the stack. + char arcHeaderBuffer[64]; + u8* arcHeader = (u8*)ALIGN_NEXT((u32)arcHeaderBuffer, 0x20); + JKRDvdToMainRam(entryNum, arcHeader, EXPAND_SWITCH_UNKNOWN2, sizeof(SArcHeader), + NULL, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + DCInvalidateRange(arcHeader, sizeof(SArcHeader)); + + alignedSize = JKRDecompExpandSize(arcHeader); + buffer = (u8*)JKRAllocFromHeap(heap, alignedSize, sizeof(SArcHeader)); + JUT_ASSERT(660, buffer); + JKRDvdToMainRam(entryNum, buffer, EXPAND_SWITCH_UNKNOWN1, alignedSize, NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + + *returnResource = buffer; + return alignedSize; + } + } + + case COMPRESSION_YAZ0: { + buffer = (u8*)JKRAllocFromHeap(heap, alignedSize, sizeof(SArcHeader)); + JUT_ASSERT(672, buffer); + + JKRDvdToMainRam(entryNum, buffer, EXPAND_SWITCH_UNKNOWN1, size, NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, NULL); + + *returnResource = buffer; + return alignedSize; + } + + case COMPRESSION_YAY0: { + OSPanic(__FILE__, 683, "Sorry, not prepared for SZP archive.\n"); + return 0; + } + + default: { + OSPanic(__FILE__, 688, ":::??? bad sequence\n"); + return 0; + } + } } /* 802BB6F8-802BB82C .text getExpandedResSize__13JKRDvdArchiveCFPCv */ -void JKRDvdArchive::getExpandedResSize(const void*) const { - /* Nonmatching */ +u32 JKRDvdArchive::getExpandedResSize(const void* resource) const { + u32 resourceSize; + if (!mExpandedSize) { + return getResSize(resource); + } + + SDIFileEntry* fileEntry = findPtrResource(resource); + if (!fileEntry) { + return -1; + } + + if (!fileEntry->isCompressed()) { + return getResSize(resource); + } + + resourceSize = getExpandSize(fileEntry); + if (resourceSize) { + return resourceSize; + } + + // The dst pointer to JKRDvdToMainRam should be aligned to 32 bytes. This will align arcHeader + // to 32 bytes on the stack. + char buffer[64]; + u8* arcHeader = (u8*)ALIGN_NEXT((u32)buffer, 0x20); + JKRDvdToMainRam(mEntryNum, arcHeader, EXPAND_SWITCH_UNKNOWN2, sizeof(SArcHeader), NULL, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, + this->field_0x64 + fileEntry->data_offset, NULL); + DCInvalidateRange(arcHeader, sizeof(SArcHeader)); + + resourceSize = JKRDecompExpandSize(arcHeader); + // ??? + ((JKRDvdArchive*)this)->setExpandSize(fileEntry, resourceSize); + + return resourceSize; } diff --git a/src/JSystem/JKernel/JKRMemArchive.cpp b/src/JSystem/JKernel/JKRMemArchive.cpp index 8acaf10f0..3216b6c56 100644 --- a/src/JSystem/JKernel/JKRMemArchive.cpp +++ b/src/JSystem/JKernel/JKRMemArchive.cpp @@ -4,74 +4,253 @@ // #include "JSystem/JKernel/JKRMemArchive.h" -#include "dolphin/types.h" +#include "JSystem/JKernel/JKRDecomp.h" +#include "JSystem/JKernel/JKRDvdRipper.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JUtility/JUTAssert.h" +#include "MSL_C/string.h" /* 802B9568-802B95A4 .text __ct__13JKRMemArchiveFv */ -JKRMemArchive::JKRMemArchive() { - /* Nonmatching */ -} +JKRMemArchive::JKRMemArchive() {} /* 802B95A4-802B9658 .text __ct__13JKRMemArchiveFlQ210JKRArchive15EMountDirection */ -JKRMemArchive::JKRMemArchive(long, JKRArchive::EMountDirection) { - /* Nonmatching */ +JKRMemArchive::JKRMemArchive(s32 entryNum, JKRArchive::EMountDirection mountDirection) : JKRArchive(entryNum, MOUNT_MEM) { + mIsMounted = false; + mMountDirection = mountDirection; + if (!open(entryNum, mMountDirection)) { + return; + } + + mVolumeType = 'RARC'; + mVolumeName = mStringTable + mNodes->name_offset; + + getVolumeList().prepend(&mFileLoaderLink); + mIsMounted = true; } /* 802B9658-802B9700 .text __dt__13JKRMemArchiveFv */ JKRMemArchive::~JKRMemArchive() { - /* Nonmatching */ + if (mIsMounted == true) { + if (mIsOpen) { + if (mArcHeader) + JKRFreeToHeap(mHeap, mArcHeader); + } + + getVolumeList().remove(&mFileLoaderLink); + mIsMounted = false; + } } /* 802B9700-802B9740 .text fixedInit__13JKRMemArchiveFl */ -void JKRMemArchive::fixedInit(long) { - /* Nonmatching */ +void JKRMemArchive::fixedInit(s32 param_1) { + mIsMounted = false; + mMountMode = 1; + mMountCount = 1; + field_0x58 = 2; + mHeap = JKRHeap::sCurrentHeap; + mEntryNum = param_1; + if (sCurrentVolume) return; + sCurrentVolume = this; + setCurrentDirID(0); } /* 802B9740-802B9810 .text mountFixed__13JKRMemArchiveFPv15JKRMemBreakFlag */ -void JKRMemArchive::mountFixed(void*, JKRMemBreakFlag) { - /* Nonmatching */ +bool JKRMemArchive::mountFixed(void* param_1, JKRMemBreakFlag param_2) { + if (check_mount_already((long)param_1)) { + return false; + } + fixedInit((long)param_1); + if (!open(param_1, 0xffff, param_2)) { + return false; + } + mVolumeType = 'RARC'; + mVolumeName = mStringTable + mNodes->name_offset; + sVolumeList.prepend(&mFileLoaderLink); + mIsOpen = param_2 == 1; + mIsMounted = true; + return true; } /* 802B9810-802B98FC .text unmountFixed__13JKRMemArchiveFv */ void JKRMemArchive::unmountFixed() { - /* Nonmatching */ + JUT_ASSERT(337, isMounted()); + JUT_ASSERT(340, mMountCount == 1); + if (sCurrentVolume == this) { + sCurrentVolume = NULL; + } + if (mIsOpen && mArcHeader) { + JKRHeap::free(mArcHeader, mHeap); + } + sVolumeList.remove(&mFileLoaderLink); + mIsMounted = false; } /* 802B98FC-802B9A90 .text open__13JKRMemArchiveFlQ210JKRArchive15EMountDirection */ -void JKRMemArchive::open(long, JKRArchive::EMountDirection) { - /* Nonmatching */ +bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirection) { + mArcHeader = NULL; + mArcInfoBlock = NULL; + mArchiveData = NULL; + mNodes = NULL; + mFiles = NULL; + mStringTable = NULL; + mIsOpen = false; + mMountDirection = mountDirection; + + if (mMountDirection == JKRArchive::MOUNT_DIRECTION_HEAD) { + u32 loadedSize; + mArcHeader = (SArcHeader *)JKRDvdRipper::loadToMainRAM( + entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, + 0, (int *)&mCompression); + } else { + u32 loadedSize; + mArcHeader = (SArcHeader *)JKRDvdRipper::loadToMainRAM( + entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap, + JKRDvdRipper::ALLOC_DIRECTION_BACKWARD, 0, (int *)&mCompression); + } + + if (!mArcHeader) { + mMountMode = UNKNOWN_MOUNT_MODE; + } else { + JUT_ASSERT(418, mArcHeader->signature =='RARC'); + mArcInfoBlock = (SArcDataInfo *)((u8 *)mArcHeader + mArcHeader->header_length); + mNodes = (SDIDirEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->node_offset); + mFiles = (SDIFileEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->file_entry_offset); + mStringTable = (char *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->string_table_offset); + + mArchiveData = + (u8 *)((u32)mArcHeader + mArcHeader->header_length + mArcHeader->file_data_offset); + mIsOpen = true; + } + if (mMountMode == 0) { + OSReport(":::Cannot alloc memory [%s][%d]\n", __FILE__, 440); + } + + return (mMountMode == UNKNOWN_MOUNT_MODE) ? false : true; } /* 802B9A90-802B9B90 .text open__13JKRMemArchiveFPvUl15JKRMemBreakFlag */ -void JKRMemArchive::open(void*, unsigned long, JKRMemBreakFlag) { - /* Nonmatching */ +bool JKRMemArchive::open(void* buffer, u32 bufferSize, JKRMemBreakFlag flag) { + mArcHeader = (SArcHeader *)buffer; + JUT_ASSERT(471, mArcHeader->signature =='RARC'); + mArcInfoBlock = (SArcDataInfo *)((u8 *)mArcHeader + mArcHeader->header_length); + mNodes = (SDIDirEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->node_offset); + mFiles = (SDIFileEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->file_entry_offset); + mStringTable = (char *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->string_table_offset); + mArchiveData = (u8 *)(((u32)mArcHeader + mArcHeader->header_length) + mArcHeader->file_data_offset); + mIsOpen = (flag == JKRMEMBREAK_FLAG_UNKNOWN1) ? true : false; // mIsOpen might be u8 + mHeap = JKRHeap::findFromRoot(buffer); + mCompression = COMPRESSION_NONE; + return true; } /* 802B9B90-802B9C34 .text fetchResource__13JKRMemArchiveFPQ210JKRArchive12SDIFileEntryPUl */ -void JKRMemArchive::fetchResource(JKRArchive::SDIFileEntry*, unsigned long*) { - /* Nonmatching */ +void* JKRMemArchive::fetchResource(SDIFileEntry* fileEntry, u32* resourceSize) { + JUT_ASSERT(535, isMounted()); + if (!fileEntry->data) { + fileEntry->data = mArchiveData + fileEntry->data_offset; + } + + if (resourceSize) { + *resourceSize = fileEntry->data_size; + } + + return fileEntry->data; } /* 802B9C34-802B9D38 .text fetchResource__13JKRMemArchiveFPvUlPQ210JKRArchive12SDIFileEntryPUl */ -void JKRMemArchive::fetchResource(void*, unsigned long, JKRArchive::SDIFileEntry*, unsigned long*) { - /* Nonmatching */ +void* JKRMemArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* fileEntry, u32* resourceSize) { + JUT_ASSERT(575, isMounted()); + u32 srcLength = fileEntry->data_size; + if (srcLength > bufferSize) { + srcLength = bufferSize; + } + + if (fileEntry->data != NULL) { + memcpy(buffer, fileEntry->data, srcLength); + } else { + JKRCompression compression = JKRConvertAttrToCompressionType(fileEntry->getAttr()); + void* data = mArchiveData + fileEntry->data_offset; + srcLength = + fetchResource_subroutine((u8*)data, srcLength, (u8*)buffer, bufferSize, compression); + } + + if (resourceSize) { + *resourceSize = srcLength; + } + + return buffer; } /* 802B9D38-802B9DE8 .text removeResourceAll__13JKRMemArchiveFv */ void JKRMemArchive::removeResourceAll() { - /* Nonmatching */ + JUT_ASSERT(622, isMounted()); + + if (mArcInfoBlock == NULL) + return; + if (mMountMode == MOUNT_MEM) + return; + + // !@bug: looping over file entries without incrementing the fileEntry pointer. Thus, only the + // first fileEntry will clear/remove the resource data. + SDIFileEntry* fileEntry = mFiles; + for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) { + if (fileEntry->data) { + fileEntry->data = NULL; + } + } } /* 802B9DE8-802B9E80 .text removeResource__13JKRMemArchiveFPv */ -void JKRMemArchive::removeResource(void*) { - /* Nonmatching */ +bool JKRMemArchive::removeResource(void* resource) { + JUT_ASSERT(653, isMounted()); + + SDIFileEntry* fileEntry = findPtrResource(resource); + if (!fileEntry) + return false; + + fileEntry->data = NULL; + return true; } /* 802B9E80-802B9F50 .text fetchResource_subroutine__13JKRMemArchiveFPUcUlPUcUli */ -void JKRMemArchive::fetchResource_subroutine(unsigned char*, unsigned long, unsigned char*, unsigned long, int) { - /* Nonmatching */ +u32 JKRMemArchive::fetchResource_subroutine(u8* src, u32 srcLength, u8* dst, u32 dstLength, int compression) { + switch (compression) { + case COMPRESSION_NONE: + if (srcLength > dstLength) { + srcLength = dstLength; + } + + memcpy(dst, src, srcLength); + return srcLength; + + case COMPRESSION_YAY0: + case COMPRESSION_YAZ0: + u32 expendedSize = JKRDecompExpandSize(src); + srcLength = expendedSize; + if (expendedSize > dstLength) { + srcLength = dstLength; + } + + JKRDecompress(src, dst, srcLength, 0); + return srcLength; + + default: + OSPanic(__FILE__, 703, ":::??? bad sequence\n"); + break; + } + + return 0; } /* 802B9F50-802B9FE0 .text getExpandedResSize__13JKRMemArchiveCFPCv */ -void JKRMemArchive::getExpandedResSize(const void*) const { - /* Nonmatching */ +u32 JKRMemArchive::getExpandedResSize(const void* resource) const { + SDIFileEntry* fileEntry = findPtrResource(resource); + if (fileEntry == NULL) + return -1; + + if (fileEntry->isCompressed() == false) { + return getResSize(resource); + } else { + return JKRDecompExpandSize((u8*)resource); + } }