diff --git a/include/JSystem/JKernel/JKRAramStream.h b/include/JSystem/JKernel/JKRAramStream.h index 9cbd22435..cdbfbd5ca 100644 --- a/include/JSystem/JKernel/JKRAramStream.h +++ b/include/JSystem/JKernel/JKRAramStream.h @@ -64,4 +64,8 @@ inline JKRAramStream* JKRCreateAramStreamManager(long priority) { return JKRAramStream::create(priority); } +inline JKRAramStreamCommand* JKRStreamToAram_Async(JSUFileInputStream *stream, u32 addr, u32 size, u32 offset, void (*callback)(u32)) { + return JKRAramStream::write_StreamToAram_Async(stream, addr, size, offset); +} + #endif /* JKRARAMSTREAM_H */ diff --git a/include/JSystem/JKernel/JKRDvdAramRipper.h b/include/JSystem/JKernel/JKRDvdAramRipper.h index 3561a7e99..6c3ba1de7 100644 --- a/include/JSystem/JKernel/JKRDvdAramRipper.h +++ b/include/JSystem/JKernel/JKRDvdAramRipper.h @@ -13,23 +13,22 @@ public: ~JKRADCommand(); /* 0x00 */ JSULink mLink; - /* 0x10 */ int field_0x10; - /* 0x14 */ int field_0x14; - /* 0x18 */ int field_0x18; - /* 0x1C */ int field_0x1c; - /* 0x20 */ int field_0x20; - /* 0x24 */ int field_0x24; - /* 0x28 */ JKRDvdFile* mDvdFile; - /* 0x2C */ u32 field_0x2c; - /* 0x30 */ JKRAramBlock* mBlock; + /* 0x10 */ JKRDvdFile* mDvdFile; + /* 0x14 */ u32 mOffset; + /* 0x18 */ u32 field_0x18; + /* 0x1C */ u32 mAddress; + /* 0x20 */ JKRAramBlock* mBlock; + /* 0x24 */ JKRExpandSwitch mExpandSwitch; + /* 0x28 */ int field_0x28; + /* 0x2C */ int field_0x2c; + /* 0x30 */ int field_0x30; /* 0x34 */ int field_0x34; - /* 0x38 */ void (*field_0x38)(u32); - /* 0x3C */ u32 field_0x3c; - /* 0x40 */ u32 field_0x40; - /* 0x44 */ u32* field_0x44; - /* 0x48 */ int field_0x48; - /* 0x4C */ u8 field_0x4c; - /* 0x50 */ JKRAramStreamCommand* mStreamCommand; + /* 0x38 */ int field_0x38; + /* 0x3C */ int field_0x3c; + /* 0x40 */ void (*mCallback)(u32); + /* 0x44 */ int field_0x44; + /* 0x48 */ bool field_0x48; + /* 0x4C */ JKRAramStreamCommand* mStreamCommand; }; class JKRDvdFile; @@ -42,11 +41,12 @@ public: static JKRADCommand* callCommand_Async(JKRADCommand*); static bool syncAram(JKRADCommand*, int); + static u32 getSzpBufferSize() { return sSzpBufferSize; } static void setSzpBufferSize(u32 size) { sSzpBufferSize = size; } - // TODO: fix type - static u8 sDvdAramAsyncList[12]; + static JSUList sDvdAramAsyncList; static u32 sSzpBufferSize; + static bool errorRetry; }; inline JKRAramBlock *JKRDvdToAram(s32 entrynum, u32 p2, JKRExpandSwitch expSwitch, u32 p4, u32 p5) { diff --git a/src/JSystem/JKernel/JKRDvdAramRipper.cpp b/src/JSystem/JKernel/JKRDvdAramRipper.cpp index 0d2b2612c..9a6dfafef 100644 --- a/src/JSystem/JKernel/JKRDvdAramRipper.cpp +++ b/src/JSystem/JKernel/JKRDvdAramRipper.cpp @@ -4,74 +4,420 @@ // #include "JSystem/JKernel/JKRDvdAramRipper.h" -#include "dolphin/types.h" +#include "JSystem/JKernel/JKRAram.h" +#include "JSystem/JKernel/JKRAramPiece.h" +#include "JSystem/JKernel/JKRAramStream.h" +#include "JSystem/JKernel/JKRDecomp.h" +#include "JSystem/JKernel/JKRDvdFile.h" +#include "JSystem/JKernel/JKRHeap.h" +#include "JSystem/JSupport/JSUFileStream.h" +#include "JSystem/JUtility/JUTAssert.h" +#include "MSL_C/string.h" +#include "dolphin/os/OSCache.h" +#include "dolphin/os/OSInterrupt.h" +#include "dolphin/vi/vi.h" +#include "global.h" + +static int JKRDecompressFromDVDToAram(JKRDvdFile*, u32, u32, u32, u32, u32); +static int decompSZS_subroutine(u8*, u32); +static u8* firstSrcData(); +static u8* nextSrcData(u8*); +static u32 dmaBufferFlush(u32); /* 802BDA14-802BDAB0 .text loadToAram__16JKRDvdAramRipperFlUl15JKRExpandSwitchUlUl */ -void JKRDvdAramRipper::loadToAram(long, unsigned long, JKRExpandSwitch, unsigned long, unsigned long) { - /* Nonmatching */ +JKRAramBlock* JKRDvdAramRipper::loadToAram(s32 entryNumber, u32 address, JKRExpandSwitch expandSwitch, u32 param_3, u32 param_4) { + JKRDvdFile dvdFile; + if (!dvdFile.open(entryNumber)) { + return NULL; + } else { + return loadToAram(&dvdFile, address, expandSwitch, param_3, param_4); + } } /* 802BDAB0-802BDB50 .text loadToAram__16JKRDvdAramRipperFP10JKRDvdFileUl15JKRExpandSwitchUlUl */ -void JKRDvdAramRipper::loadToAram(JKRDvdFile*, unsigned long, JKRExpandSwitch, unsigned long, unsigned long) { - /* Nonmatching */ +JKRAramBlock* JKRDvdAramRipper::loadToAram(JKRDvdFile* dvdFile, u32 address, JKRExpandSwitch expandSwitch, u32 param_3, u32 param_4) { + JKRADCommand* command = loadToAram_Async(dvdFile, address, expandSwitch, NULL, param_3, param_4); + syncAram(command, 0); + + if (command->field_0x44 < 0) { + delete command; + return NULL; + } + + if (address) { + delete command; + return (JKRAramBlock*)-1; + } + + JKRAramBlock* result = command->mBlock; + delete command; + return result; } +bool JKRDvdAramRipper::errorRetry = true; + /* 802BDB50-802BDBFC .text loadToAram_Async__16JKRDvdAramRipperFP10JKRDvdFileUl15JKRExpandSwitchPFUl_vUlUl */ -void JKRDvdAramRipper::loadToAram_Async(JKRDvdFile*, unsigned long, JKRExpandSwitch, void (*)(unsigned long), unsigned long, unsigned long) { - /* Nonmatching */ +JKRADCommand* JKRDvdAramRipper::loadToAram_Async(JKRDvdFile* dvdFile, u32 address, JKRExpandSwitch expandSwitch, void (*callback)(u32), u32 param_4, u32 param_5) { + JKRADCommand* command = new (JKRGetSystemHeap(), -4) JKRADCommand(); + command->mDvdFile = dvdFile; + command->mAddress = address; + command->mBlock = NULL; + command->mExpandSwitch = expandSwitch; + command->mCallback = callback; + command->mOffset = param_4; + command->field_0x18 = param_5; + + if (!callCommand_Async(command)) { + delete command; + return NULL; + } + + return command; } +JSUList JKRDvdAramRipper::sDvdAramAsyncList; + /* 802BDBFC-802BDF34 .text callCommand_Async__16JKRDvdAramRipperFP12JKRADCommand */ -void JKRDvdAramRipper::callCommand_Async(JKRADCommand*) { +JKRADCommand* JKRDvdAramRipper::callCommand_Async(JKRADCommand* command) { /* Nonmatching */ -} + s32 compression; + s32 uncompressedSize; + bool bVar1 = true; + JKRDvdFile* dvdFile = command->mDvdFile; + compression = 0; + OSLockMutex(&dvdFile->mMutex2); -/* 802BDF34-802BDFA4 .text __dt__18JSUFileInputStreamFv */ -JSUFileInputStream::~JSUFileInputStream() { - /* Nonmatching */ + if (dvdFile->field_0x50) { + bVar1 = false; + } else { + dvdFile->field_0x50 = OSGetCurrentThread(); + JSUFileInputStream* stream = new (JKRGetSystemHeap(), -4) JSUFileInputStream(dvdFile); + dvdFile->mFileStream = stream; + u32 fileSize = dvdFile->getFileSize(); + if (command->field_0x18 && fileSize > command->field_0x18) { + fileSize = command->field_0x18; + } + fileSize = ALIGN_NEXT(fileSize, 0x20); + if (command->mExpandSwitch == 1) { + u8 buffer[0x40]; + u8* bufPtr = (u8*)ALIGN_NEXT((u32)&buffer, 0x20); + while (true) { + if (DVDReadPrio(dvdFile->getFileInfo(), bufPtr, 0x20, 0, 2) >= 0) { + break; + } + + if (errorRetry == 0) { + delete stream; + return NULL; + } + + VIWaitForRetrace(); + } + DCInvalidateRange(bufPtr, 0x20); + + compression = JKRCheckCompressed(bufPtr); + uncompressedSize = JKRDecompExpandSize(bufPtr); + if (command->field_0x18 && command->field_0x18 > uncompressedSize) { + uncompressedSize = command->field_0x18; + } + } + + if (compression == 0) { + command->mExpandSwitch = EXPAND_SWITCH_UNKNOWN0; + } + + if (command->mExpandSwitch == EXPAND_SWITCH_UNKNOWN1) { + if (command->mAddress == 0 && command->mBlock == NULL) { + command->mBlock = + JKRAram::getAramHeap()->alloc(uncompressedSize, JKRAramHeap::HEAD); + if (command->mBlock) { + command->mAddress = command->mBlock->mAddress; + } + dvdFile->mBlock = command->mBlock; + } + + if (command->mBlock) { + command->mAddress = command->mBlock->mAddress; + } + + if (command->mAddress == 0) { + dvdFile->field_0x50 = NULL; + return NULL; + } + } else { + if (command->mAddress == 0 && !command->mBlock) { + command->mBlock = JKRAram::getAramHeap()->alloc(fileSize, JKRAramHeap::HEAD); + } + + if (command->mBlock) { + command->mAddress = command->mBlock->mAddress; + } + + if (command->mAddress == 0) { + dvdFile->field_0x50 = NULL; + return NULL; + } + } + + if (compression == 0) { + command->mStreamCommand = JKRStreamToAram_Async(stream, command->mAddress, fileSize - command->mOffset, command->mOffset, NULL); + } else if (compression == 1) { + command->mStreamCommand = JKRStreamToAram_Async(stream, command->mAddress, fileSize - command->mOffset, command->mOffset, NULL); + } else if (compression == 2) { + command->mStreamCommand = NULL; + JKRDecompressFromDVDToAram(command->mDvdFile, command->mAddress, fileSize, uncompressedSize, command->mOffset, 0); + } + + if (!command->mCallback) { + (*((JSUList*)&sDvdAramAsyncList)).append(&command->mLink); + } else { + command->mCallback((u32)command); + } + } + + OSUnlockMutex(&dvdFile->mMutex2); + return bVar1 == true ? command : NULL; } /* 802BDFA4-802BE078 .text syncAram__16JKRDvdAramRipperFP12JKRADCommandi */ -void JKRDvdAramRipper::syncAram(JKRADCommand*, int) { - /* Nonmatching */ +bool JKRDvdAramRipper::syncAram(JKRADCommand* command, int param_1) { + JKRDvdFile* dvdFile = command->mDvdFile; + OSLockMutex(&dvdFile->mMutex2); + + if (command->mStreamCommand) { + JKRAramStreamCommand* var1 = JKRAramStream::sync(command->mStreamCommand, param_1); + command->field_0x44 = -(var1 == NULL); + + if (param_1 != 0 && var1 == NULL) { + OSUnlockMutex(&dvdFile->mMutex2); + return false; + } + } + + (*((JSUList*)&sDvdAramAsyncList)).remove(&command->mLink); + if (command->mStreamCommand) { + delete command->mStreamCommand; + } + + delete dvdFile->mFileStream; + dvdFile->field_0x50 = NULL; + OSUnlockMutex(&dvdFile->mMutex2); + return true; } /* 802BE078-802BE0B8 .text __ct__12JKRADCommandFv */ -JKRADCommand::JKRADCommand() { - /* Nonmatching */ +JKRADCommand::JKRADCommand() : mLink(this) { + field_0x44 = 0; + field_0x48 = false; } /* 802BE0B8-802BE144 .text __dt__12JKRADCommandFv */ JKRADCommand::~JKRADCommand() { - /* Nonmatching */ + if (field_0x48 == true) { + delete mDvdFile; + } } +static OSMutex decompMutex; +u32 JKRDvdAramRipper::sSzpBufferSize = 0x00000400; +static u8* szpBuf; +static u8* szpEnd; +static u8* refBuf; +static u8* refEnd; +static u8* refCurrent; +static u8* dmaBuf; +static u8* dmaEnd; +static u8* dmaCurrent; +static u32 srcOffset; +static u32 transLeft; +static u8* srcLimit; +static JKRDvdFile* srcFile; +static u32 fileOffset; +static int readCount; +static u32 maxDest; +static bool isInitMutex; + /* 802BE144-802BE34C .text JKRDecompressFromDVDToAram__FP10JKRDvdFileUlUlUlUlUl */ -void JKRDecompressFromDVDToAram(JKRDvdFile*, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) { - /* Nonmatching */ +static int JKRDecompressFromDVDToAram(JKRDvdFile* dvdFile, u32 param_1, u32 fileSize, u32 uncompressedSize, u32 param_4, u32 param_5) { + BOOL level = OSDisableInterrupts(); + if (!isInitMutex) { + OSInitMutex(&decompMutex); + isInitMutex = true; + } + + OSRestoreInterrupts(level); + OSLockMutex(&decompMutex); + u32 bufferSize = JKRDvdAramRipper::getSzpBufferSize(); + szpBuf = (u8*)JKRAllocFromSysHeap(bufferSize, 0x20); + JUT_ASSERT(693, szpBuf != 0); + szpEnd = szpBuf + bufferSize; + refBuf = (u8*)JKRAllocFromSysHeap(0x1120, 0); + JUT_ASSERT(701, refBuf != 0); + refEnd = refBuf + 0x1120; + refCurrent = refBuf; + dmaBuf = (u8*)JKRAllocFromSysHeap(0x100, 0x20); + JUT_ASSERT(710, dmaBuf != 0); + dmaEnd = dmaBuf + 0x100; + dmaCurrent = dmaBuf; + srcFile = dvdFile; + srcOffset = param_5; + transLeft = fileSize - param_5; + fileOffset = param_4; + readCount = 0; + maxDest = uncompressedSize; + u8* first = firstSrcData(); + int result = first ? decompSZS_subroutine(first, param_1) : -1; + JKRHeap::free(szpBuf, 0); + JKRHeap::free(refBuf, 0); + JKRHeap::free(dmaBuf, 0); + OSUnlockMutex(&decompMutex); + return result; } /* 802BE34C-802BE5C0 .text decompSZS_subroutine__FPUcUl */ -void decompSZS_subroutine(unsigned char*, unsigned long) { - /* Nonmatching */ +static int decompSZS_subroutine(u8* src, u32 dest) { + u32 endAddr; + s32 validBitCount = 0; + u32 currCodeByte = 0; + u32 startDest = dest; + + if (src[0] != 'Y' || src[1] != 'a' || src[2] != 'z' || src[3] != '0') { + return -1; + } + + SYaz0Header* header = (SYaz0Header*)src; + endAddr = dest + (header->length - fileOffset); + if (endAddr > dest + maxDest) { + endAddr = dest + maxDest; + } + + src += 0x10; + do { + if (validBitCount == 0) { + if ((src > srcLimit) && transLeft) { + src = nextSrcData(src); + } + currCodeByte = *src; + validBitCount = 8; + src++; + } + if (currCodeByte & 0x80) { + if (readCount >= fileOffset) { + *(dmaCurrent++) = *src; + dest++; + if (dmaCurrent == dmaEnd) { + startDest += dmaBufferFlush(startDest); + } + if (dest == endAddr) { + break; + } + } + *(refCurrent++) = *src; + if (refCurrent == refEnd) { + refCurrent = refBuf; + } + readCount++; + src++; + } else { + u32 dist = ((src[0] & 0x0f) << 8) | src[1]; + s32 numBytes = src[0] >> 4; + src += 2; + u8* copySource = refCurrent - dist - 1; + if (copySource < refBuf) { + copySource += refEnd - refBuf; + } + if (numBytes == 0) { + numBytes = *src + 0x12; + src += 1; + } else { + numBytes += 2; + } + do { + if (readCount >= fileOffset) { + *(dmaCurrent++) = *copySource; + dest++; + if (dmaCurrent == dmaEnd) { + startDest += dmaBufferFlush(startDest); + } + if (dest == endAddr) { + break; + } + } + *(refCurrent++) = *copySource; + if (refCurrent == refEnd) { + refCurrent = refBuf; + } + copySource++; + if (copySource == refEnd) { + copySource = refBuf; + } + readCount++; + numBytes--; + } while (numBytes != 0); + } + currCodeByte <<= 1; + validBitCount--; + } while (dest < endAddr); + dmaBufferFlush(startDest); + return 0; } /* 802BE5C0-802BE674 .text firstSrcData__Fv */ -void firstSrcData() { - /* Nonmatching */ +static u8* firstSrcData() { + srcLimit = szpEnd - 0x19; + u8* buffer = szpBuf; + u32 bufSize = szpEnd - buffer; + u32 length = transLeft < bufSize ? transLeft : bufSize; + while (true) { + int result = DVDReadPrio(&srcFile->mFileInfo, buffer, length, 0, 2); + if (result >= 0) { + break; + } + if (JKRDvdAramRipper::errorRetry == 0) { + return NULL; + } + VIWaitForRetrace(); + } + srcOffset += length; + transLeft -= length; + return buffer; } /* 802BE674-802BE790 .text nextSrcData__FPUc */ -void nextSrcData(unsigned char*) { - /* Nonmatching */ +static u8* nextSrcData(u8* src) { + u32 size = szpEnd - src; + u8* dest = IS_NOT_ALIGNED(size, 0x20) ? szpBuf + 0x20 - (size & (0x20 - 1)) : szpBuf; + memcpy(dest, src, size); + u32 transSize = szpEnd - (dest + size); + if (transSize > transLeft) { + transSize = transLeft; + } + JUT_ASSERT(966, transSize > 0); + while (true) { + s32 result = DVDReadPrio(&srcFile->mFileInfo, dest + size, transSize, srcOffset, 2); + if (result >= 0) { + break; + } + if (JKRDvdAramRipper::errorRetry == 0) { + return NULL; + } + VIWaitForRetrace(); + } + srcOffset += transSize; + transLeft -= transSize; + if (transLeft == 0) { + srcLimit = dest + size + transSize; + } + return dest; } /* 802BE790-802BE7F8 .text dmaBufferFlush__FUl */ -void dmaBufferFlush(unsigned long) { - /* Nonmatching */ -} - -/* 802BE83C-802BE890 .text __dt__23JSUList<12JKRADCommand>Fv */ -JSUList::~JSUList() { - /* Nonmatching */ +static u32 dmaBufferFlush(u32 param_1) { + if (dmaCurrent == dmaBuf) { + return 0; + } + u32 size = ALIGN_NEXT(dmaCurrent - dmaBuf, 0x20); + JKRAramPiece::orderSync(0, (u32)dmaBuf, param_1, size, NULL); + dmaCurrent = dmaBuf; + return size; }