From 0914321a6bdb0af5ff1799f11a40e176dd529890 Mon Sep 17 00:00:00 2001 From: Roman Sandu Date: Sat, 28 Dec 2024 03:47:14 +0300 Subject: [PATCH] Steal JKRDvdArchive.cpp from TWW --- configure.py | 1 + include/JSystem/JKernel/JKRDvdArchive.hpp | 5 +- src/JSystem/JKernel/JKRDvdArchive.cpp | 366 ++++++++++++++++++++++ 3 files changed, 369 insertions(+), 3 deletions(-) create mode 100644 src/JSystem/JKernel/JKRDvdArchive.cpp diff --git a/configure.py b/configure.py index 3904d434..3b2acbef 100644 --- a/configure.py +++ b/configure.py @@ -315,6 +315,7 @@ def MatchingFor(*versions): Object(Matching, "JSystem/JKernel/JKRAramHeap.cpp"), Object(Matching, "JSystem/JKernel/JKRAram.cpp"), Object(Matching, "JSystem/JKernel/JKRDisposer.cpp"), + Object(NonMatching, "JSystem/JKernel/JKRDvdArchive.cpp"), Object(Matching, "JSystem/JKernel/JKRDvdFile.cpp"), Object(Matching, "JSystem/JKernel/JKRExpHeap.cpp"), Object(Matching, "JSystem/JKernel/JKRFileFinder.cpp"), diff --git a/include/JSystem/JKernel/JKRDvdArchive.hpp b/include/JSystem/JKernel/JKRDvdArchive.hpp index 2f882a0b..6e3630a2 100644 --- a/include/JSystem/JKernel/JKRDvdArchive.hpp +++ b/include/JSystem/JKernel/JKRDvdArchive.hpp @@ -10,8 +10,7 @@ struct JKRDvdArchive : public JKRArchive { virtual ~JKRDvdArchive(); // _00 virtual void* fetchResource(SDIFileEntry* entry, u32* outSize); // _38 virtual void* fetchResource(void* resourceBuffer, u32 bufferSize, - SDIFileEntry* entry, u32* resSize, - JKRExpandSwitch expandSwitch); // _3C + SDIFileEntry* entry, u32* resSize); // _3C bool open(s32); static u32 fetchResource_subroutine(s32, u32, u32, u8*, u32, int, int); @@ -20,7 +19,7 @@ struct JKRDvdArchive : public JKRArchive { // _00 = VTBL // _00-_5C = JKRArchive - int _60; // _60 + s32 mDataOffset; // _60 JKRFile* mDvdFile; // _64 }; diff --git a/src/JSystem/JKernel/JKRDvdArchive.cpp b/src/JSystem/JKernel/JKRDvdArchive.cpp new file mode 100644 index 00000000..5817eecd --- /dev/null +++ b/src/JSystem/JKernel/JKRDvdArchive.cpp @@ -0,0 +1,366 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +JKRDvdArchive::JKRDvdArchive(s32 entryNum, + JKRArchive::EMountDirection mountDirection) + : JKRArchive(entryNum, MOUNT_DVD) +{ + mMountDirection = mountDirection; + if (!open(entryNum)) + return; + + mVolumeType = 'RARC'; + mVolumeName = mStrTable + mDirectories->mOffset; + getVolumeList().prepend(&mFileLoaderLink); + mIsMounted = true; +} + +JKRDvdArchive::~JKRDvdArchive() +{ + if (mIsMounted == true) { + if (mArcInfoBlock) { + SDIFileEntry* fileEntry = mFileEntries; + int i = 0; + for (; i < mArcInfoBlock->num_file_entries; fileEntry++, i++) { + if (fileEntry->mData) { + JKRFreeToHeap(mHeap, fileEntry->mData); + } + } + + JKRFreeToHeap(mHeap, mArcInfoBlock); + mArcInfoBlock = nullptr; + } + + // if (mExpandedSize) { + // JKRFree(mExpandedSize); + // mExpandedSize = nullptr; + // } + + if (mDvdFile) { + delete mDvdFile; + } + + getVolumeList().remove(&mFileLoaderLink); + mIsMounted = false; + } +} + +static void dummy() +{ + OSReport(__FILE__); + OSReport("isMounted()"); + OSReport("Halt"); + OSReport("mMountCount == 1"); +} + +bool JKRDvdArchive::open(s32 entryNum) +{ + int alignment; + u8 useCompression; + SDIFileEntry* fileEntry; + + mArcInfoBlock = nullptr; + mDataOffset = nullptr; + mDirectories = nullptr; + mFileEntries = nullptr; + mStrTable = nullptr; + + 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_DECOMPRESS, + sizeof(SArcHeader), nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, 0, &mCompression); + + 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_DECOMPRESS, + arcHeader->file_data_offset, nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, sizeof(SArcHeader), + nullptr); + + mDirectories = (SDIDirEntry*)((int)&mArcInfoBlock->num_nodes + + mArcInfoBlock->node_offset); + mFileEntries = (SDIFileEntry*)((int)&mArcInfoBlock->num_nodes + + mArcInfoBlock->file_entry_offset); + mStrTable = (char*)((int)&mArcInfoBlock->num_nodes + + mArcInfoBlock->string_table_offset); + // mExpandedSize = nullptr; + + useCompression = 0; + fileEntry = mFileEntries; + for (u32 i = 0; i < mArcInfoBlock->num_file_entries; fileEntry++, i++) { + if (FLAG_ON(fileEntry->getAttr(), 1)) { + useCompression |= fileEntry->getCompressFlag(); + } + } + + if (useCompression) { + s32* 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); + } + + mDataOffset = 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; +} + +void* JKRDvdArchive::fetchResource(SDIFileEntry* fileEntry, u32* returnSize) +{ + JUT_ASSERT(413, isMounted()); + u32 tempReturnSize; + if (returnSize == nullptr) { + returnSize = &tempReturnSize; + } + + JKRCompression fileCompression + = JKRConvertAttrToCompressionType(fileEntry->getAttr()); + if (!fileEntry->mData) { + u8* resourcePtr; + u32 resourceSize = fetchResource_subroutine( + mEntryNum, this->mDataOffset + fileEntry->mDataOffset, + fileEntry->mDataOffset, mHeap, fileCompression, mCompression, + &resourcePtr); + *returnSize = resourceSize; + if (resourceSize == 0) { + return nullptr; + } + + fileEntry->mData = resourcePtr; + if (fileCompression == JKR_COMPRESSION_YAZ0) { + // setExpandSize(fileEntry, *returnSize); + } + } else { + if (fileCompression == JKR_COMPRESSION_YAZ0) { + // u32 resourceSize = getExpandSize(fileEntry); + // *returnSize = resourceSize; + } else { + *returnSize = fileEntry->mSize; + } + } + + return fileEntry->mData; +} + +void* JKRDvdArchive::fetchResource(void* buffer, u32 bufferSize, + SDIFileEntry* fileEntry, u32* returnSize) +{ + JUT_ASSERT(489, isMounted()); + u32 expandSize; + u32 size = fileEntry->mSize; + JKRCompression fileCompression + = JKRConvertAttrToCompressionType(fileEntry->getAttr()); + + if (!fileEntry->mData) { + bufferSize = (s32)ALIGN_PREV(bufferSize, 0x20); + size = fetchResource_subroutine( + mEntryNum, mDataOffset + fileEntry->mDataOffset, fileEntry->mSize, + (u8*)buffer, bufferSize, fileCompression, mCompression); + } else { + if (fileCompression == JKR_COMPRESSION_YAZ0) { + // expandSize = getExpandSize(fileEntry); + if (expandSize) { + size = expandSize; + } + } + + if (size > bufferSize) { + size = bufferSize; + } + + JKRHeap::copyMemory(buffer, fileEntry->mData, size); + } + + if (returnSize) { + *returnSize = size; + } + return buffer; +} + +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 JKR_COMPRESSION_NONE: { + switch (fileCompression) { + case JKR_COMPRESSION_NONE: + if (alignedSize > alignedDstLength) { + alignedSize = alignedDstLength; + } + + JKRDvdToMainRam(entryNum, dst, EXPAND_SWITCH_DEFAULT, alignedSize, + nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, + offset, nullptr); + return alignedSize; + case JKR_COMPRESSION_YAY0: + case JKR_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_NONE, + sizeof(SArcHeader), nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, + nullptr); + DCInvalidateRange(arcHeader, sizeof(SArcHeader)); + + u32 decompressedSize = JKRDecompExpandSize(arcHeader); + u32 alignedDecompressedSize = ALIGN_NEXT(decompressedSize, 0x20); + if (alignedDecompressedSize > alignedDstLength) { + alignedDecompressedSize = alignedDstLength; + } + + JKRDvdToMainRam(entryNum, dst, EXPAND_SWITCH_DECOMPRESS, + alignedDecompressedSize, nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, + nullptr); + return decompressedSize; + } + } + + case JKR_COMPRESSION_YAZ0: { + if (size > alignedDstLength) { + size = alignedDstLength; + } + + JKRDvdToMainRam(entryNum, dst, EXPAND_SWITCH_DECOMPRESS, size, nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, nullptr); + return size; + } + + case JKR_COMPRESSION_YAY0: { + OSPanic(__FILE__, 610, "Sorry, not prepared for SZP archive.\n"); + return 0; + } + + default: { + OSPanic(__FILE__, 616, ":::??? bad sequence\n"); + return 0; + } + } +} + +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 JKR_COMPRESSION_NONE: { + switch (fileCompression) { + case JKR_COMPRESSION_NONE: + buffer + = (u8*)JKRAllocFromHeap(heap, alignedSize, sizeof(SArcHeader)); + JUT_ASSERT(VERSION_SELECT(638, 631, 631), buffer != nullptr); + + JKRDvdToMainRam( + entryNum, buffer, EXPAND_SWITCH_DEFAULT, alignedSize, nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, nullptr); + + *returnResource = buffer; + return alignedSize; + case JKR_COMPRESSION_YAY0: + case JKR_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_NONE, + sizeof(SArcHeader), nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, + nullptr); + DCInvalidateRange(arcHeader, sizeof(SArcHeader)); + + alignedSize = JKRDecompExpandSize(arcHeader); + buffer + = (u8*)JKRAllocFromHeap(heap, alignedSize, sizeof(SArcHeader)); + JUT_ASSERT(VERSION_SELECT(674, 660, 660), buffer); + JKRDvdToMainRam(entryNum, buffer, EXPAND_SWITCH_DECOMPRESS, + alignedSize, nullptr, + JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, + nullptr); + + *returnResource = buffer; + return alignedSize; + } + } + + case JKR_COMPRESSION_YAZ0: { + buffer = (u8*)JKRAllocFromHeap(heap, alignedSize, sizeof(SArcHeader)); + JUT_ASSERT(VERSION_SELECT(686, 672, 672), buffer); + + JKRDvdToMainRam(entryNum, buffer, EXPAND_SWITCH_DECOMPRESS, size, + nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, offset, + nullptr); + + *returnResource = buffer; + return alignedSize; + } + + case JKR_COMPRESSION_YAY0: { + OSPanic(__FILE__, 697, "Sorry, not prepared for SZP archive.\n"); + return 0; + } + + default: { + OSPanic(__FILE__, 702, ":::??? bad sequence\n"); + return 0; + } + } +}