From 265bb1e8c2c178dac45ab082dd66c3a1922e9efb Mon Sep 17 00:00:00 2001 From: Roman Sandu Date: Fri, 27 Dec 2024 04:34:17 +0300 Subject: [PATCH] Stole a metric ton of JKernel from TWW --- configure.py | 15 +- include/JSystem/JKernel/JKRAram.hpp | 113 +++++ include/JSystem/JKernel/JKRAramPiece.hpp | 76 +++ include/JSystem/JKernel/JKRAramStream.hpp | 77 +++ include/JSystem/JKernel/JKRArchive.hpp | 6 +- include/JSystem/JKernel/JKRDecomp.hpp | 80 ++++ include/JSystem/JKernel/JKRDvdFile.hpp | 3 + include/JSystem/JKernel/JKRDvdRipper.hpp | 67 +++ include/JSystem/JKernel/JKREnum.hpp | 9 +- include/dolphin/ar.h | 8 + include/macros.h | 6 + src/JSystem/JKernel/JKRAram.cpp | 549 ++++++++++++++++++++++ src/JSystem/JKernel/JKRAramPiece.cpp | 155 ++++++ src/JSystem/JKernel/JKRAramStream.cpp | 214 +++++++++ src/JSystem/JKernel/JKRDecomp.cpp | 289 ++++++++++++ src/JSystem/JKernel/JKRDvdRipper.cpp | 465 ++++++++++++++++++ 16 files changed, 2120 insertions(+), 12 deletions(-) create mode 100644 include/JSystem/JKernel/JKRAramPiece.hpp create mode 100644 include/JSystem/JKernel/JKRAramStream.hpp create mode 100644 include/JSystem/JKernel/JKRDecomp.hpp create mode 100644 include/JSystem/JKernel/JKRDvdRipper.hpp create mode 100644 src/JSystem/JKernel/JKRAram.cpp create mode 100644 src/JSystem/JKernel/JKRAramPiece.cpp create mode 100644 src/JSystem/JKernel/JKRAramStream.cpp create mode 100644 src/JSystem/JKernel/JKRDecomp.cpp create mode 100644 src/JSystem/JKernel/JKRDvdRipper.cpp diff --git a/configure.py b/configure.py index 3776cd5f..81a525c2 100644 --- a/configure.py +++ b/configure.py @@ -313,16 +313,21 @@ def MatchingFor(*versions): # JKernel Object(Matching, "JSystem/JKernel/JKRAramHeap.cpp"), + Object(Matching, "JSystem/JKernel/JKRAram.cpp"), Object(Matching, "JSystem/JKernel/JKRDisposer.cpp"), - Object(Matching, "JSystem/JKernel/JKRHeap.cpp"), + Object(Matching, "JSystem/JKernel/JKRDvdFile.cpp"), Object(Matching, "JSystem/JKernel/JKRExpHeap.cpp"), - Object(Matching, "JSystem/JKernel/JKRStdHeap.cpp"), - Object(Matching, "JSystem/JKernel/JKRSolidHeap.cpp"), + Object(Matching, "JSystem/JKernel/JKRFileFinder.cpp"), Object(Matching, "JSystem/JKernel/JKRFileLoader.cpp"), + Object(Matching, "JSystem/JKernel/JKRHeap.cpp"), + Object(Matching, "JSystem/JKernel/JKRSolidHeap.cpp"), + Object(Matching, "JSystem/JKernel/JKRStdHeap.cpp"), Object(Matching, "JSystem/JKernel/JKRThread.cpp"), - Object(Matching, "JSystem/JKernel/JKRFileFinder.cpp"), - Object(Matching, "JSystem/JKernel/JKRDvdFile.cpp"), + Object(Matching, "JSystem/JKernel/JKRDvdRipper.cpp"), + Object(Matching, "JSystem/JKernel/JKRDecomp.cpp"), Object(Matching, "JSystem/JKernel/JKRAramBlock.cpp"), + Object(Matching, "JSystem/JKernel/JKRAramPiece.cpp"), + Object(Matching, "JSystem/JKernel/JKRAramStream.cpp"), # JSupport Object(Matching, "JSystem/JSupport/JSUInputStream.cpp"), diff --git a/include/JSystem/JKernel/JKRAram.hpp b/include/JSystem/JKernel/JKRAram.hpp index 7b2306ec..342948ff 100644 --- a/include/JSystem/JKernel/JKRAram.hpp +++ b/include/JSystem/JKernel/JKRAram.hpp @@ -1,6 +1,119 @@ #ifndef JKR_ARAM_HPP #define JKR_ARAM_HPP +#include +#include +#include + +class JKRHeap; +class JKRAMCommand; class JKRAramBlock; +class JKRAram : public JKRThread { +private: + JKRAram(u32, u32, s32); + virtual ~JKRAram(); + + /* vt[03] */ void* run(void); /* override */ + +public: + u32 getAudioMemory() const { return mAudioMemoryPtr; } + u32 getAudioMemSize() const { return mAudioMemorySize; } + u32 getGraphMemory() const { return mGraphMemoryPtr; } + u32 getGraphMemSize() const { return mGraphMemorySize; } + // private: + /* 0x00 */ // vtable + /* 0x04 */ // JKRThread + /* 0x68 */ u32 mAudioMemoryPtr; + /* 0x6C */ u32 mAudioMemorySize; + /* 0x70 */ u32 mGraphMemoryPtr; + /* 0x74 */ u32 mGraphMemorySize; + /* 0x78 */ u32 mAramMemoryPtr; + /* 0x7C */ u32 mAramMemorySize; + /* 0x80 */ JKRAramHeap* mAramHeap; + /* 0x84 */ u32 mStackArray[3]; + +public: + static JKRAram* create(u32, u32, s32, s32, s32); + static bool checkOkAddress(u8*, u32, JKRAramBlock*, u32); + static void changeGroupIdIfNeed(u8*, int); + static JKRAramBlock* mainRamToAram(u8*, u32, u32, JKRExpandSwitch, u32, + JKRHeap*, int); + static JKRAramBlock* mainRamToAram(u8*, JKRAramBlock*, u32, JKRExpandSwitch, + u32, JKRHeap*, int); + static u8* aramToMainRam(u32, u8*, u32, JKRExpandSwitch, u32, JKRHeap*, int, + u32*); + static u8* aramToMainRam(JKRAramBlock*, u8*, u32, u32, JKRExpandSwitch, u32, + JKRHeap*, int, u32*); + static void dump(void); + + static JKRAram* getManager() { return sAramObject; } + static JKRAramHeap* getAramHeap() { return getManager()->mAramHeap; } + static JSUList& getCommandList() { return sAramCommandList; } + + static u8 decideAramGroupId(int groupId) + { + JKRAramHeap* heap; + u8 finalGroupId; + + if (groupId < 0) { + return getAramHeap()->getCurrentGroupID(); + } + + return (u8)groupId; + } + + static u32 getSzpBufferSize() { return szpBufferSize; } + static void setSzpBufferSize(u32 size) { szpBufferSize = size; } + + static OSMessageQueue sMessageQueue; + +private: + static JKRAram* sAramObject; + static u32 szpBufferSize; + static OSMessage sMessageBuffer[4]; + static JSUList sAramCommandList; +}; + +inline JKRAramBlock* JKRAllocFromAram(u32 size, + JKRAramHeap::EAllocMode allocMode) +{ + return JKRAram::getAramHeap()->alloc(size, allocMode); +} + +inline void JKRFreeToAram(JKRAramBlock* block) +{ + JKRAram::getAramHeap()->free(block); +} + +inline u8* JKRAramToMainRam(u32 p1, u8* p2, u32 p3, JKRExpandSwitch p4, u32 p5, + JKRHeap* p6, int p7, u32* p8) +{ + return JKRAram::aramToMainRam(p1, p2, p3, p4, p5, p6, p7, p8); +} + +inline u8* +JKRAramToMainRam(JKRAramBlock* block, u8* dst, u32 size, u32 p4 = 0, + JKRExpandSwitch expandSwitch = EXPAND_SWITCH_DEFAULT, + u32 p5 = 0, JKRHeap* heap = nullptr, int p6 = -1, u32* p7 = 0) +{ + return JKRAram::aramToMainRam(block, dst, size, p4, expandSwitch, p5, heap, + p6, p7); +} + +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); +} + +inline JKRAramBlock* JKRMainRamToAram(u8* buf, JKRAramBlock* block, u32 size, + JKRExpandSwitch expandSwitch, + u32 fileSize, JKRHeap* heap, int id) +{ + return JKRAram::mainRamToAram(buf, block, size, expandSwitch, fileSize, + heap, id); +} #endif diff --git a/include/JSystem/JKernel/JKRAramPiece.hpp b/include/JSystem/JKernel/JKRAramPiece.hpp new file mode 100644 index 00000000..b313213c --- /dev/null +++ b/include/JSystem/JKernel/JKRAramPiece.hpp @@ -0,0 +1,76 @@ +#ifndef JKR_ARAM_PIECE_HPP +#define JKR_ARAM_PIECE_HPP + +#include +#include +#include +#include + +class JKRAramBlock; +class JKRDecompCommand; +class JKRAMCommand { +public: + typedef void (*AsyncCallback)(u32); + + JKRAMCommand(); + ~JKRAMCommand(); + +public: + /* 0x00 */ ARQRequest mRequest; + /* 0x20 */ JSULink mPieceLink; + /* 0x30 */ JSULink field_0x30; + + /* 0x40 */ s32 mTransferDirection; + /* 0x44 */ u32 mDataLength; + /* 0x48 */ u32 mSrc; + /* 0x4C */ u32 mDst; + /* 0x50 */ JKRAramBlock* mAramBlock; + /* 0x54 */ u32 field_0x54; + /* 0x58 */ AsyncCallback mCallback; + /* 0x5C */ OSMessageQueue* field_0x5C; + /* 0x60 */ s32 field_0x60; + /* 0x64 */ JKRDecompCommand* mDecompCommand; + /* 0x68 */ OSMessageQueue mMessageQueue; + /* 0x88 */ OSMessage mMessage; + /* 0x8C */ void* field_0x8C; + /* 0x90 */ void* field_0x90; + /* 0x94 */ void* field_0x94; +}; + +class JKRAramPiece { +public: + static OSMutex mMutex; + // TODO: fix type + static JSUList sAramPieceCommandList; + +public: + struct Message { + s32 field_0x00; + JKRAMCommand* command; + }; + +public: + static JKRAMCommand* prepareCommand(int, u32, u32, u32, JKRAramBlock*, + JKRAMCommand::AsyncCallback); + static void sendCommand(JKRAMCommand*); + + static JKRAMCommand* orderAsync(int, u32, u32, u32, JKRAramBlock*, + JKRAMCommand::AsyncCallback); + static BOOL sync(JKRAMCommand*, int); + static BOOL orderSync(int, u32, u32, u32, JKRAramBlock*); + static void startDMA(JKRAMCommand*); + static void doneDMA(u32); + +private: + static void lock() { OSLockMutex(&mMutex); } + static void unlock() { OSUnlockMutex(&mMutex); } +}; + +inline BOOL JKRAramPcs(int direction, u32 source, u32 destination, u32 length, + JKRAramBlock* block) +{ + return JKRAramPiece::orderSync(direction, source, destination, length, + block); +} + +#endif diff --git a/include/JSystem/JKernel/JKRAramStream.hpp b/include/JSystem/JKernel/JKRAramStream.hpp new file mode 100644 index 00000000..32d24ebb --- /dev/null +++ b/include/JSystem/JKernel/JKRAramStream.hpp @@ -0,0 +1,77 @@ +#ifndef JKR_ARAM_STREAM_HPP +#define JKR_ARAM_STREAM_HPP + +#include + +class JSUFileInputStream; + +class JKRAramStreamCommand { +public: + enum Type { + UNKNOWN = 0, + READ = 1, + WRITE = 2, + }; + + JKRAramStreamCommand(); + +public: + /* 0x00 */ Type mType; + /* 0x04 */ u32 mAddress; + /* 0x08 */ u32 mSize; + /* 0x0C */ u32 field_0x0c; + /* 0x10 */ JSUFileInputStream* mStream; + /* 0x14 */ u32 mOffset; + /* 0x18 */ u8* mTransferBuffer; + /* 0x1C */ u32 mTransferBufferSize; + /* 0x20 */ JKRHeap* mHeap; + /* 0x24 */ bool mAllocatedTransferBuffer; + /* 0x25 */ u8 padding_0x29[3]; + /* 0x28 */ u32 field_0x2c; + /* 0x2C */ OSMessageQueue mMessageQueue; + /* 0x4C */ OSMessage mMessage; + /* 0x50 */ u32 field_0x54; + /* 0x54 */ u32 field_0x58; +}; + +class JKRAramStream : public JKRThread { +private: + JKRAramStream(s32); + virtual ~JKRAramStream(); + + /* vt[03] */ void* run(void); /* override */ + +public: + static JKRAramStream* create(s32); + + static s32 readFromAram(void); + static s32 writeToAram(JKRAramStreamCommand*); + static JKRAramStreamCommand* write_StreamToAram_Async(JSUFileInputStream*, + u32, u32, u32); + static JKRAramStreamCommand* sync(JKRAramStreamCommand*, BOOL); + static void setTransBuffer(u8*, u32, JKRHeap*); + +private: + static JKRAramStream* sAramStreamObject; + static OSMessage sMessageBuffer[4]; + static OSMessageQueue sMessageQueue; + + static u8* transBuffer; + static u32 transSize; + static JKRHeap* transHeap; +}; + +inline JKRAramStream* JKRCreateAramStreamManager(s32 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 diff --git a/include/JSystem/JKernel/JKRArchive.hpp b/include/JSystem/JKernel/JKRArchive.hpp index f09036a7..20c2e4dd 100644 --- a/include/JSystem/JKernel/JKRArchive.hpp +++ b/include/JSystem/JKernel/JKRArchive.hpp @@ -178,11 +178,11 @@ class JKRArchive : public JKRFileLoader { { int compression; if (FLAG_ON(attr, JKRARCHIVE_ATTR_COMPRESSION)) - compression = JKRCOMPRESSION_NONE; + compression = JKR_COMPRESSION_NONE; else if (!FLAG_ON(attr, JKRARCHIVE_ATTR_YAY0)) - compression = JKRCOMPRESSION_YAZ0; + compression = JKR_COMPRESSION_YAZ0; else - compression = JKRCOMPRESSION_YAY0; + compression = JKR_COMPRESSION_YAY0; return compression; } diff --git a/include/JSystem/JKernel/JKRDecomp.hpp b/include/JSystem/JKernel/JKRDecomp.hpp new file mode 100644 index 00000000..f8f29487 --- /dev/null +++ b/include/JSystem/JKernel/JKRDecomp.hpp @@ -0,0 +1,80 @@ +#ifndef JKR_DECOMP_HPP +#define JKR_DECOMP_HPP + +#include +#include + +class JKRAMCommand; +class JKRDecompCommand { +public: + typedef void (*AsyncCallback)(u32); + + JKRDecompCommand(); + ~JKRDecompCommand(); + +public: + /* 0x00 */ u32 field_0x0; + /* 0x04 */ u8* mSrcBuffer; + /* 0x08 */ u8* mDstBuffer; + /* 0x0C */ u32 mSrcLength; + /* 0x10 */ u32 mDstLength; + /* 0x14 */ AsyncCallback mCallback; + /* 0x18 */ JKRDecompCommand* mThis; + /* 0x1C */ OSMessageQueue* field_0x1c; + /* 0x20 */ s32 field_0x20; + /* 0x24 */ JKRAMCommand* mAMCommand; + /* 0x28 */ OSMessageQueue mMessageQueue; + /* 0x48 */ OSMessage mMessage; +}; + +#define JKRDECOMP_SYNC_BLOCKING 0 +#define JKRDECOMP_SYNC_NON_BLOCKING 1 + +class JKRDecomp : public JKRThread { +private: + JKRDecomp(s32); + virtual ~JKRDecomp(); + + /* vt[03] */ virtual void* run(); /* override */ + +public: + static JKRDecomp* create(s32); + static JKRDecompCommand* prepareCommand(u8*, u8*, u32, u32, + JKRDecompCommand::AsyncCallback); + static void sendCommand(JKRDecompCommand*); + static bool sync(JKRDecompCommand*, int); + static JKRDecompCommand* orderAsync(u8*, u8*, u32, u32, + JKRDecompCommand::AsyncCallback); + static bool orderSync(u8*, u8*, u32, u32); + static void decode(u8*, u8*, u32, u32); + static void decodeSZP(u8*, u8*, u32, u32); + static void decodeSZS(u8*, u8*, u32, u32); + static JKRCompression checkCompressed(u8*); + + static JKRDecomp* sDecompObject; + static OSMessage sMessageBuffer[4]; + static OSMessageQueue sMessageQueue; +}; + +inline void JKRDecompress(u8* srcBuffer, u8* dstBuffer, u32 srcLength, + u32 dstLength) +{ + JKRDecomp::orderSync(srcBuffer, dstBuffer, srcLength, dstLength); +} + +inline JKRDecomp* JKRCreateDecompManager(s32 priority) +{ + return JKRDecomp::create(priority); +} + +inline JKRCompression JKRCheckCompressed(u8* pBuf) +{ + return JKRDecomp::checkCompressed(pBuf); +} + +inline u32 JKRDecompExpandSize(u8* pBuf) +{ + return (pBuf[4] << 24) | (pBuf[5] << 16) | (pBuf[6] << 8) | pBuf[7]; +} + +#endif diff --git a/include/JSystem/JKernel/JKRDvdFile.hpp b/include/JSystem/JKernel/JKRDvdFile.hpp index dffb07f8..571aa753 100644 --- a/include/JSystem/JKernel/JKRDvdFile.hpp +++ b/include/JSystem/JKernel/JKRDvdFile.hpp @@ -9,6 +9,8 @@ class JKRAramBlock; class JSUFileInputStream; class JKRDvdFile; +// TODO: tww doesn't think this exists, maybe get rid of it? + struct JKRDvdFileInfo : DVDFileInfo { JKRDvdFile* mFile; }; @@ -28,6 +30,7 @@ class JKRDvdFile : public JKRFile { virtual int writeData(const void* data, s32 length, s32 offset); virtual s32 getFileSize() const { return mDvdFileInfo.length; } virtual bool open(s32 entrynum); + DVDFileInfo* getFileInfo() { return &mDvdFileInfo; } s32 sync(); static void doneProcess(s32 result, DVDFileInfo* info); diff --git a/include/JSystem/JKernel/JKRDvdRipper.hpp b/include/JSystem/JKernel/JKRDvdRipper.hpp new file mode 100644 index 00000000..fd345e90 --- /dev/null +++ b/include/JSystem/JKernel/JKRDvdRipper.hpp @@ -0,0 +1,67 @@ +#ifndef JKRDVDRIPPER_H +#define JKRDVDRIPPER_H + +#include +#include + +struct SYaz0Header { + u32 signature; + u32 length; +}; + +class JKRDMCommand { + JKRDMCommand(); + ~JKRDMCommand(); +}; + +class JKRHeap; +class JKRDvdFile; +class JKRDvdRipper { +public: + static JSUList sDvdAsyncList; + static u32 szpBufferSize; + static bool errorRetry; + + enum EAllocDirection { + DEFAULT_EALLOC_DIRECTION = 0, + ALLOC_DIRECTION_FORWARD = 1, + ALLOC_DIRECTION_BACKWARD = 2, + }; + + static void setSzpBufferSize(u32 size) { szpBufferSize = size; } + + static void* loadToMainRAM(char const*, u8*, JKRExpandSwitch, u32, JKRHeap*, + EAllocDirection, u32, int*); + static void* loadToMainRAM(s32, u8*, JKRExpandSwitch, u32, JKRHeap*, + EAllocDirection, u32, int*); + static void* loadToMainRAM(JKRDvdFile*, u8*, JKRExpandSwitch, u32, JKRHeap*, + EAllocDirection, u32, int*); + + static bool isErrorRetry(void) { return errorRetry; } + inline static u32 getSzpBufferSize() { return szpBufferSize; } +}; + +// void JKRDecompressFromDVD(JKRDvdFile*, void*, u32, u32, u32, u32, u32*); + +inline void* JKRDvdToMainRam(s32 entryNum, u8* dst, + JKRExpandSwitch expandSwitch, u32 dstLength, + JKRHeap* heap, + JKRDvdRipper::EAllocDirection allocDirection, + u32 offset, int* returnSize) +{ + return JKRDvdRipper::loadToMainRAM(entryNum, dst, expandSwitch, dstLength, + heap, allocDirection, offset, + returnSize); +} + +inline void* JKRDvdToMainRam(const char* name, u8* dst, + JKRExpandSwitch expandSwitch, u32 dstLength, + JKRHeap* heap, + JKRDvdRipper::EAllocDirection allocDirection, + u32 offset, int* returnSize) +{ + return JKRDvdRipper::loadToMainRAM(name, dst, expandSwitch, dstLength, heap, + allocDirection, offset, returnSize); +} + +#endif /* JKRDVDRIPPER_H */ diff --git a/include/JSystem/JKernel/JKREnum.hpp b/include/JSystem/JKernel/JKREnum.hpp index f7edadd2..35ec79ce 100644 --- a/include/JSystem/JKernel/JKREnum.hpp +++ b/include/JSystem/JKernel/JKREnum.hpp @@ -1,10 +1,11 @@ #ifndef JKR_ENUM_H #define JKR_ENUM_H -#define JKRCOMPRESSION_NONE 0 -#define JKRCOMPRESSION_YAY0 1 -#define JKRCOMPRESSION_YAZ0 2 -#define JKRCOMPRESSION_ASR 3 +typedef int JKRCompression; +const JKRCompression JKR_COMPRESSION_NONE = 0; +const JKRCompression JKR_COMPRESSION_YAY0 = 1; +const JKRCompression JKR_COMPRESSION_YAZ0 = 2; +const JKRCompression JKR_COMPRESSION_ASR = 3; enum JKRExpandSwitch { EXPAND_SWITCH_DEFAULT, /* Do nothing? treated same as 2 */ diff --git a/include/dolphin/ar.h b/include/dolphin/ar.h index 3ef1e3d5..0177fdc4 100644 --- a/include/dolphin/ar.h +++ b/include/dolphin/ar.h @@ -34,6 +34,10 @@ typedef struct ARQRequest ARQRequest; #define ARQ_PRIORITY_LOW 0 #define ARQ_PRIORITY_HIGH 1 +#ifdef __cplusplus +extern "C" { +#endif + // ar.c ARQCallback ARRegisterDMACallback(ARQCallback callback); u32 ARGetDMAStatus(void); @@ -59,4 +63,8 @@ void ARQFlushQueue(void); void ARQSetChunkSize(u32 size); u32 ARQGetChunkSize(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/macros.h b/include/macros.h index 671cf984..e8436e35 100644 --- a/include/macros.h +++ b/include/macros.h @@ -7,6 +7,12 @@ #define ALIGN_PREV(u, align) (u & (~(align - 1))) #define ALIGN_NEXT(u, align) ((u + (align - 1)) & (~(align - 1))) +#define IS_ALIGNED(X, N) (((X) & ((N)-1)) == 0) +#define IS_NOT_ALIGNED(X, N) (((X) & ((N)-1)) != 0) + +#define READU32_BE(ptr, offset) \ + (((u32)ptr[offset] << 24) | ((u32)ptr[offset + 1] << 16) | ((u32)ptr[offset + 2] << 8) | \ + (u32)ptr[offset + 3]); #ifdef DEBUG #define ASSERTLINE(line, cond) \ diff --git a/src/JSystem/JKernel/JKRAram.cpp b/src/JSystem/JKernel/JKRAram.cpp new file mode 100644 index 00000000..f2dc338f --- /dev/null +++ b/src/JSystem/JKernel/JKRAram.cpp @@ -0,0 +1,549 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "string.h" +#include "macros.h" + +static int JKRDecompressFromAramToMainRam(u32, void*, u32, u32, u32); +static int decompSZS_subroutine(u8*, u8*); +static u8* firstSrcData(); +static u8* nextSrcData(u8*); + +JKRAram* JKRAram::sAramObject; + +/* 802B42C4-802B4360 .text create__7JKRAramFUlUllll */ +JKRAram* JKRAram::create(u32 aram_audio_buffer_size, u32 aram_audio_graph_size, + s32 stream_priority, s32 decomp_priority, + s32 piece_priority) +{ + if (!sAramObject) { + sAramObject = new (JKRHeap::getSystemHeap(), 0) JKRAram( + aram_audio_buffer_size, aram_audio_graph_size, piece_priority); + } + + JKRCreateAramStreamManager(stream_priority); + JKRCreateDecompManager(decomp_priority); + sAramObject->resume(); + return sAramObject; +} + +OSMessage JKRAram::sMessageBuffer[4] = { nullptr, nullptr, nullptr, nullptr }; +OSMessageQueue JKRAram::sMessageQueue = { 0 }; + +JKRAram::JKRAram(u32 audio_buffer_size, u32 audio_graph_size, s32 priority) + : JKRThread(0x4000, 0x10, priority) +{ + u32 aramBase = ARInit(mStackArray, ARRAY_COUNT(mStackArray)); + ARQInit(); + + u32 aramSize = ARGetSize(); + OSReport("ARAM size = %08x\n", aramSize); + + mAudioMemorySize = audio_buffer_size; + if (audio_graph_size == 0xFFFFFFFF) { + mGraphMemorySize = (aramSize - audio_buffer_size) - aramBase; + mAramMemorySize = 0; + } else { + mGraphMemorySize = audio_graph_size; + mAramMemorySize + = (aramSize - (audio_buffer_size + audio_graph_size)) - aramBase; + } + + mAudioMemoryPtr = ARAlloc(mAudioMemorySize); + mGraphMemoryPtr = ARAlloc(mGraphMemorySize); + + if (mAramMemorySize) { + mAramMemoryPtr = ARAlloc(mAramMemorySize); + } else { + mAramMemoryPtr = nullptr; + } + OSReport("ARAM audio area %08x: %08x\n", mAudioMemoryPtr, mAudioMemorySize); + OSReport("ARAM graph area %08x: %08x\n", mGraphMemoryPtr, mGraphMemorySize); + OSReport("ARAM user area %08x: %08x\n", mAramMemoryPtr, mAramMemorySize); + + mAramHeap = new (JKRHeap::getSystemHeap(), 0) + JKRAramHeap(mGraphMemoryPtr, mGraphMemorySize); +} + +JKRAram::~JKRAram() +{ + sAramObject = nullptr; + if (mAramHeap) { + delete mAramHeap; + } +} + +void* JKRAram::run() +{ + int result; + JKRAMCommand* command; + JKRAramPiece::Message* message; + OSInitMessageQueue(&sMessageQueue, sMessageBuffer, 4); + do { + OSReceiveMessage(&sMessageQueue, (OSMessage*)&message, + OS_MESSAGE_BLOCK); + result = message->field_0x00; + command = message->command; + delete message; + + switch (result) { + case 1: + JKRAramPiece::startDMA(command); + break; + } + } while (true); +} + +bool JKRAram::checkOkAddress(u8* addr, u32 size, JKRAramBlock* block, + u32 param_4) +{ + if (!IS_ALIGNED((u32)addr, 0x20) && !IS_ALIGNED(size, 0x20)) { + OSPanic(__FILE__, 226, ":::address not 32Byte aligned."); + return false; + } + + if (block && !IS_ALIGNED((u32)block->getAddress() + param_4, 0x20)) { + OSPanic(__FILE__, 235, ":::address not 32Byte aligned."); + return false; + } + return true; +} + +void JKRAram::changeGroupIdIfNeed(u8* data, int groupId) +{ + if (groupId < 0) { + return; + } + JKRHeap* currentHeap = JKRHeap::getCurrentHeap(); + if (currentHeap->getHeapType() == 'EXPH') { + JKRExpHeap::CMemBlock* block = JKRExpHeap::CMemBlock::getBlock(data); + block->newGroupId(groupId); + } +} + +JKRAramBlock* JKRAram::mainRamToAram(u8* buf, u32 bufSize, u32 alignedSize, + JKRExpandSwitch expandSwitch, u32 fileSize, + JKRHeap* heap, int id) +{ + JKRAramBlock* block = nullptr; + checkOkAddress(buf, bufSize, nullptr, 0); + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS) { + expandSwitch = (JKRCheckCompressed(buf) == JKR_COMPRESSION_NONE) + ? EXPAND_SWITCH_DEFAULT + : EXPAND_SWITCH_DECOMPRESS; + } + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS) { + u32 expandSize = JKRCheckCompressed(buf) != JKR_COMPRESSION_NONE + ? JKRDecompExpandSize(buf) + : 0; + if (fileSize == 0 || fileSize > expandSize) { + fileSize = expandSize; + } + if (bufSize == 0) { + JKRAramBlock* allocatedBlock + = (JKRAramBlock*)JKRAllocFromAram(fileSize, JKRAramHeap::HEAD); + block = (JKRAramBlock*)allocatedBlock; + if (allocatedBlock == nullptr) + return nullptr; + + allocatedBlock->newGroupID(decideAramGroupId(id)); + bufSize = allocatedBlock->getAddress(); + } + if (alignedSize == 0 || alignedSize > expandSize) + alignedSize = expandSize; + + if (fileSize > alignedSize) + fileSize = alignedSize; + + void* allocatedMem = JKRAllocFromHeap(heap, fileSize, -32); + if (allocatedMem == nullptr) { + if (block != nullptr) { + JKRFreeToAram(block); + } + block = nullptr; + } else { + JKRDecompress(buf, (u8*)allocatedMem, fileSize, 0); + JKRAramPcs(0, (u32)allocatedMem, bufSize, alignedSize, block); + JKRFreeToHeap(heap, allocatedMem); + block = block == nullptr ? (JKRAramBlock*)-1 : block; + } + } else { + if (bufSize == 0) { + + JKRAramBlock* allocatedBlock = (JKRAramBlock*)JKRAllocFromAram( + alignedSize, JKRAramHeap::HEAD); + block = allocatedBlock; + block->newGroupID(decideAramGroupId(id)); + if (block == nullptr) + return nullptr; + + bufSize = allocatedBlock->getAddress(); + } + + JKRAramPcs(0, (u32)buf, bufSize, alignedSize, block); + block = block == nullptr ? (JKRAramBlock*)-1 : block; + } + return block; +} + +JKRAramBlock* JKRAram::mainRamToAram(u8* buf, JKRAramBlock* block, + u32 alignedSize, + JKRExpandSwitch expandSwitch, u32 fileSize, + JKRHeap* heap, int id) +{ + checkOkAddress(buf, 0, block, 0); + if (!block) { + return mainRamToAram(buf, u32(0), alignedSize, expandSwitch, fileSize, + heap, id); + } + u32 blockSize = block->mSize; + if (expandSwitch == 1) { + fileSize = fileSize >= blockSize ? blockSize : fileSize; + } + return mainRamToAram(buf, block->mAddress, + alignedSize > blockSize ? blockSize : alignedSize, + expandSwitch, fileSize, heap, id); +} + +u8* JKRAram::aramToMainRam(u32 address, u8* buf, u32 p3, + JKRExpandSwitch expandSwitch, u32 p5, JKRHeap* heap, + int id, u32* pSize) +{ + JKRCompression compression = JKR_COMPRESSION_NONE; + if (pSize != nullptr) + *pSize = 0; + + checkOkAddress(buf, address, nullptr, 0); + + u32 expandSize; + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS) { + u8 buffer[64]; + u8* bufPtr = (u8*)ALIGN_NEXT((u32)buffer, 32); + JKRAramPcs(1, address, (u32)bufPtr, sizeof(buffer) / 2, + nullptr); // probably change sizeof(buffer) / 2 to 32 + compression = JKRCheckCompressed(bufPtr); + expandSize = JKRDecompExpandSize(bufPtr); + } + + if (compression == JKR_COMPRESSION_YAZ0) { // SZS + if (p5 != 0 && p5 < expandSize) + expandSize = p5; + + if (buf == nullptr) + buf = (u8*)JKRAllocFromHeap(heap, expandSize, 32); + if (buf == nullptr) + return nullptr; + else { + changeGroupIdIfNeed(buf, id); + JKRDecompressFromAramToMainRam(address, buf, p3, expandSize, 0); + if (pSize != nullptr) { + *pSize = expandSize; + } + return buf; + } + } else if (compression == JKR_COMPRESSION_YAY0) { // SZP + u8* szpSpace = (u8*)JKRAllocFromHeap(heap, p3, -32); + if (szpSpace == nullptr) { + return nullptr; + } else { + JKRAramPcs(1, address, (u32)szpSpace, p3, nullptr); + if (p5 != 0 && p5 < expandSize) + expandSize = p5; + + u8* rv; + if (buf == nullptr) { + rv = (u8*)JKRAllocFromHeap(heap, expandSize, 32); + } else { + rv = buf; + } + + if (rv == nullptr) { + JKRFree(szpSpace); + return nullptr; + } else { + changeGroupIdIfNeed(rv, id); + JKRDecompress(szpSpace, rv, expandSize, 0); + JKRFreeToHeap(heap, szpSpace); + if (pSize != nullptr) { + *pSize = expandSize; + } + return rv; + } + } + } else { // Not compressed or ASR + if (buf == nullptr) + buf = (u8*)JKRAllocFromHeap(heap, p3, 32); + if (buf == nullptr) { + return nullptr; + } else { + changeGroupIdIfNeed(buf, id); + JKRAramPcs(1, address, (u32)buf, p3, nullptr); + if (pSize != nullptr) { + *pSize = p3; + } + return buf; + } + } +} + +u8* JKRAram::aramToMainRam(JKRAramBlock* block, u8* buf, u32 p3, u32 p4, + JKRExpandSwitch expandSwitch, u32 p6, JKRHeap* heap, + int id, u32* pSize) +{ + if (pSize) { + *pSize = 0; + } + checkOkAddress(buf, 0, block, p4); + if (!block) { + OSPanic(__FILE__, 690, ":::Bad Aram Block specified.\n"); + } + if (p4 >= block->mSize) { + return nullptr; + } + p3 = p3 == 0 ? block->mSize : p3; + if (p4 + p3 > block->mSize) { + p3 = block->mSize - p4; + } + return aramToMainRam(p4 + block->mAddress, buf, p3, expandSwitch, p6, heap, + id, pSize); +} + +static void dummy() +{ + OSReport( + "---------------- BAD SYNC. you'd set callback, but now call sync.\n"); +} +JSUList JKRAram::sAramCommandList; +static OSMutex decompMutex; +u32 JKRAram::szpBufferSize = 0x00000400; +static u8* szpBuf; +static u8* szpEnd; +static u8* refBuf; +static u8* refEnd; +static u8* refCurrent; +static u32 srcOffset; +static u32 transLeft; +static u8* srcLimit; +static u32 srcAddress; +static u32 fileOffset; +static u32 readCount; +static u32 maxDest; +static bool isInitMutex; + +static int JKRDecompressFromAramToMainRam(u32 src, void* dst, u32 srcLength, + u32 dstLength, u32 offset) +{ + BOOL interrupts = OSDisableInterrupts(); + if (isInitMutex == false) { + OSInitMutex(&decompMutex); + isInitMutex = true; + } + OSRestoreInterrupts(interrupts); + OSLockMutex(&decompMutex); + + u32 szsBufferSize = JKRAram::getSzpBufferSize(); + szpBuf = (u8*)JKRAllocFromSysHeap(szsBufferSize, 32); + JUT_ASSERT(VERSION_SELECT(1091, 1077, 1077), szpBuf != nullptr); + + szpEnd = szpBuf + szsBufferSize; + if (offset != 0) { + refBuf = (u8*)JKRAllocFromSysHeap(0x1120, 0); + JUT_ASSERT(VERSION_SELECT(1100, 1086, 1086), refBuf != nullptr); + refEnd = refBuf + 0x1120; + refCurrent = refBuf; + } else { + refBuf = nullptr; + } + srcAddress = src; + srcOffset = 0; + transLeft = (srcLength != 0) ? srcLength : -1; + fileOffset = offset; + readCount = 0; + maxDest = dstLength; + + u8* data = firstSrcData(); + u32 decompressedSize = ((u32*)data)[1]; + decompSZS_subroutine(data, (u8*)dst); + JKRFree(szpBuf); + if (refBuf) { + JKRFree(refBuf); + } + + DCStoreRangeNoSync(dst, decompressedSize); + OSUnlockMutex(&decompMutex); + + return 0; +} + +static int decompSZS_subroutine(u8* src, u8* dest) +{ + u8* endPtr; + s32 validBitCount = 0; + s32 currCodeByte = 0; + u32 ts = 0; + + if (src[0] != 'Y' || src[1] != 'a' || src[2] != 'z' || src[3] != '0') { + return -1; + } + + SYaz0Header* header = (SYaz0Header*)src; + endPtr = dest + (header->length - fileOffset); + if (endPtr > dest + maxDest) { + endPtr = dest + maxDest; + } + + src += 0x10; + do { + if (validBitCount == 0) { + if ((src > srcLimit) && transLeft) { + src = nextSrcData(src); + } + currCodeByte = *src; + validBitCount = 8; + src++; + } + if (currCodeByte & 0x80) { + if (fileOffset != 0) { + if (readCount >= fileOffset) { + *dest = *src; + dest++; + ts++; + if (dest == endPtr) { + break; + } + } + *(refCurrent++) = *src; + if (refCurrent == refEnd) { + refCurrent = refBuf; + } + src++; + } else { + *dest = *src; + dest++; + src++; + ts++; + if (dest == endPtr) { + break; + } + } + readCount++; + } else { + u32 dist = ((src[0] & 0x0f) << 8) | src[1]; + s32 numBytes = src[0] >> 4; + src += 2; + u8* copySource; + if (fileOffset != 0) { + copySource = refCurrent - dist - 1; + if (copySource < refBuf) { + copySource += refEnd - refBuf; + } + } else { + copySource = dest - dist - 1; + } + if (numBytes == 0) { + numBytes = *src + 0x12; + src += 1; + } else { + numBytes += 2; + } + if (fileOffset != 0) { + do { + if (readCount >= fileOffset) { + *dest = *copySource; + dest++; + ts++; + if (dest == endPtr) { + break; + } + } + *(refCurrent++) = *copySource; + if (refCurrent == refEnd) { + refCurrent = refBuf; + } + copySource++; + if (copySource == refEnd) { + copySource = refBuf; + } + readCount++; + numBytes--; + } while (numBytes != 0); + } else { + do { + *dest = *copySource; + dest++; + ts++; + if (dest == endPtr) { + break; + } + readCount++; + numBytes--; + copySource++; + } while (numBytes != 0); + } + } + currCodeByte <<= 1; + validBitCount--; + } while (dest < endPtr); + return 0; +} + +static u8* firstSrcData() +{ + srcLimit = szpEnd - 0x19; + u8* buffer = szpBuf; + + u32 length; + u32 size = szpEnd - szpBuf; + if (transLeft < size) { + length = transLeft; + } else { + length = size; + } + + u32 src = (u32)(srcAddress + srcOffset); + u32 dst = (u32)buffer; + u32 alignedLength = ALIGN_NEXT(length, 0x20); + JKRAramPcs(1, src, dst, alignedLength, nullptr); + + srcOffset += length; + transLeft -= length; + if (!transLeft) { + srcLimit = buffer + length; + } + + return buffer; +} + +static u8* nextSrcData(u8* current) +{ + u8* dest; + u32 left = (u32)(szpEnd - current); + if (IS_NOT_ALIGNED(left, 0x20)) { + dest = szpBuf + 0x20 - (left & (0x20 - 1)); + } else { + dest = szpBuf; + } + + memcpy(dest, current, left); + u32 transSize = (u32)(szpEnd - (dest + left)); + if (transSize > transLeft) { + transSize = transLeft; + } + JUT_ASSERT(VERSION_SELECT(1376, 1361, 1361), transSize > 0); + + JKRAramPcs(1, (u32)(srcAddress + srcOffset), ((u32)dest + left), + ALIGN_NEXT(transSize, 0x20), nullptr); + srcOffset += transSize; + transLeft -= transSize; + + if (transLeft == 0) + srcLimit = (dest + left) + transSize; + + return dest; +} diff --git a/src/JSystem/JKernel/JKRAramPiece.cpp b/src/JSystem/JKernel/JKRAramPiece.cpp new file mode 100644 index 00000000..58a3dfa6 --- /dev/null +++ b/src/JSystem/JKernel/JKRAramPiece.cpp @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include + +JKRAMCommand* JKRAramPiece::prepareCommand(int direction, u32 src, u32 dst, + u32 length, JKRAramBlock* block, + JKRAMCommand::AsyncCallback callback) +{ + JKRAMCommand* command = new (JKRHeap::getSystemHeap(), -4) JKRAMCommand(); + command->mTransferDirection = direction; + command->mSrc = src; + command->mDst = dst; + command->mAramBlock = block; + command->mDataLength = length; + command->mCallback = callback; + return command; +} + +void JKRAramPiece::sendCommand(JKRAMCommand* command) { startDMA(command); } + +JSUList JKRAramPiece::sAramPieceCommandList; +OSMutex JKRAramPiece::mMutex; + +JKRAMCommand* JKRAramPiece::orderAsync(int direction, u32 source, + u32 destination, u32 length, + JKRAramBlock* block, + JKRAMCommand::AsyncCallback callback) +{ + lock(); + if ((source & 0x1f) != 0 || (destination & 0x1f) != 0) { + OSReport("direction = %x\n", direction); + OSReport("source = %x\n", source); + OSReport("destination = %x\n", destination); + OSReport("length = %x\n", length); + OSPanic(__FILE__, 102, "Abort."); + } + + Message* message = new (JKRHeap::getSystemHeap(), -4) Message(); + JKRAMCommand* command = JKRAramPiece::prepareCommand( + direction, source, destination, length, block, callback); + message->field_0x00 = 1; + message->command = command; + + OSSendMessage(&JKRAram::sMessageQueue, message, OS_MESSAGE_BLOCK); + if (command->mCallback != nullptr) { + sAramPieceCommandList.append(&command->mPieceLink); + } + + unlock(); + return command; +} + +BOOL JKRAramPiece::sync(JKRAMCommand* command, int is_non_blocking) +{ + OSMessage message; + + lock(); + if (is_non_blocking == 0) { + OSReceiveMessage(&command->mMessageQueue, &message, OS_MESSAGE_BLOCK); + sAramPieceCommandList.remove(&command->mPieceLink); + unlock(); + return TRUE; + } + + BOOL result = OSReceiveMessage(&command->mMessageQueue, &message, + OS_MESSAGE_NOBLOCK); + if (!result) { + unlock(); + return FALSE; + } + + sAramPieceCommandList.remove(&command->mPieceLink); + unlock(); + return TRUE; +} + +BOOL JKRAramPiece::orderSync(int direction, u32 source, u32 destination, + u32 length, JKRAramBlock* block) +{ + lock(); + + JKRAMCommand* command = JKRAramPiece::orderAsync( + direction, source, destination, length, block, nullptr); + BOOL result = JKRAramPiece::sync(command, 0); + delete command; + + unlock(); + return result; +} + +void JKRAramPiece::startDMA(JKRAMCommand* command) +{ + if (command->mTransferDirection == 1) { + DCInvalidateRange((void*)command->mDst, command->mDataLength); + } else { + DCStoreRange((void*)command->mSrc, command->mDataLength); + } + + ARQPostRequest(&command->mRequest, 0, command->mTransferDirection, 0, + command->mSrc, command->mDst, command->mDataLength, + JKRAramPiece::doneDMA); +} + +void JKRAramPiece::doneDMA(u32 requestAddress) +{ + JKRAMCommand* command = (JKRAMCommand*)requestAddress; + + if (command->mTransferDirection == 1) { + DCInvalidateRange((void*)command->mDst, command->mDataLength); + } + + if (command->field_0x60 != 0) { + if (command->field_0x60 == 2) { + JKRDecomp::sendCommand(command->mDecompCommand); + } + return; + } + + if (command->mCallback) { + (*command->mCallback)(requestAddress); + } else if (command->field_0x5C) { + OSSendMessage(command->field_0x5C, command, OS_MESSAGE_NOBLOCK); + } else { + OSSendMessage(&command->mMessageQueue, command, OS_MESSAGE_NOBLOCK); + } +} + +JKRAMCommand::JKRAMCommand() + : mPieceLink(this) + , field_0x30(this) +{ + OSInitMessageQueue(&mMessageQueue, &mMessage, OS_MESSAGE_BLOCK); + mCallback = nullptr; + field_0x5C = nullptr; + field_0x60 = 0; + field_0x8C = nullptr; + field_0x90 = nullptr; + field_0x94 = nullptr; +} + +JKRAMCommand::~JKRAMCommand() +{ + if (field_0x8C) { + delete field_0x8C; + } + if (field_0x90) { + delete field_0x90; + } + + if (field_0x94) { + JKRHeap::free(field_0x94, nullptr); + } +} diff --git a/src/JSystem/JKernel/JKRAramStream.cpp b/src/JSystem/JKernel/JKRAramStream.cpp new file mode 100644 index 00000000..838ed6d6 --- /dev/null +++ b/src/JSystem/JKernel/JKRAramStream.cpp @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include + +JKRAramStream* JKRAramStream::sAramStreamObject; + +/* 802B61E4-802B6254 .text create__13JKRAramStreamFl */ +JKRAramStream* JKRAramStream::create(s32 priority) +{ + if (!sAramStreamObject) { + sAramStreamObject = new (JKRGetSystemHeap(), 0) JKRAramStream(priority); + setTransBuffer(nullptr, 0, nullptr); + } + + return sAramStreamObject; +} + +void* JKRAramStream::sMessageBuffer[4] = { nullptr, nullptr, nullptr, nullptr }; +OSMessageQueue JKRAramStream::sMessageQueue = { 0 }; + +/* 802B6254-802B62A4 .text __ct__13JKRAramStreamFl */ +JKRAramStream::JKRAramStream(s32 priority) + : JKRThread(0x4000, 0x10, priority) +{ + resume(); +} + +/* 802B62A4-802B6304 .text __dt__13JKRAramStreamFv */ +JKRAramStream::~JKRAramStream() { } + +/* 802B6304-802B6374 .text run__13JKRAramStreamFv */ +void* JKRAramStream::run() +{ + OSInitMessageQueue(&sMessageQueue, sMessageBuffer, + ARRAY_COUNT(sMessageBuffer)); + + for (;;) { + OSMessage message; + OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK); + JKRAramStreamCommand* command = (JKRAramStreamCommand*)message; + + switch (command->mType) { + case JKRAramStreamCommand::READ: + readFromAram(); + break; + case JKRAramStreamCommand::WRITE: + writeToAram(command); + break; + default: + break; + } + } +} + +/* 802B6374-802B637C .text readFromAram__13JKRAramStreamFv */ +s32 JKRAramStream::readFromAram() { return 1; } + +/* 802B637C-802B6568 .text + * writeToAram__13JKRAramStreamFP20JKRAramStreamCommand */ +s32 JKRAramStream::writeToAram(JKRAramStreamCommand* command) +{ + u32 dstSize = command->mSize; + u32 offset = command->mOffset; + u32 writtenLength = 0; + u32 destination = command->mAddress; + u8* buffer = command->mTransferBuffer; + u32 bufferSize = command->mTransferBufferSize; + JKRHeap* heap = command->mHeap; + + if (buffer) { + bufferSize = (bufferSize) ? bufferSize : 0x400; + + command->mTransferBufferSize = bufferSize; + command->mAllocatedTransferBuffer = false; + } else { + bufferSize = (bufferSize) ? bufferSize : 0x400; + + if (heap) { + buffer = (u8*)JKRAllocFromHeap(heap, bufferSize, -0x20); + command->mTransferBuffer = buffer; + } else { + buffer = (u8*)JKRAllocFromHeap(nullptr, bufferSize, -0x20); + command->mTransferBuffer = buffer; + } + + command->mTransferBufferSize = bufferSize; + command->mAllocatedTransferBuffer = true; + } + + if (!buffer) { + if (!heap) { + JKRGetCurrentHeap()->dump(); + } else { + heap->dump(); + } + + OSReport(":::Cannot alloc memory [%s][%d]\n", __FILE__, 168); + OSPanic(__FILE__, 169, "abort\n"); + } + + if (buffer) { + command->mStream->seek(offset, SEEK_SET); + while (dstSize != 0) { + u32 length = (dstSize > bufferSize) ? bufferSize : dstSize; + + s32 readLength = command->mStream->read(buffer, length); + if (readLength == 0) { + writtenLength = 0; + break; + } + + JKRAramPcs(0, (u32)buffer, destination, length, nullptr); + dstSize -= length; + writtenLength += length; + destination += length; + } + + if (command->mAllocatedTransferBuffer) { + JKRFree(buffer); + command->mAllocatedTransferBuffer = false; + } + } + + OSSendMessage(&command->mMessageQueue, (OSMessage)writtenLength, + OS_MESSAGE_NOBLOCK); + return writtenLength; +} + +u8* JKRAramStream::transBuffer; +u32 JKRAramStream::transSize; +JKRHeap* JKRAramStream::transHeap; + +/* 802B6568-802B6624 .text + * write_StreamToAram_Async__13JKRAramStreamFP18JSUFileInputStreamUlUlUl */ +JKRAramStreamCommand* +JKRAramStream::write_StreamToAram_Async(JSUFileInputStream* stream, u32 addr, + u32 size, u32 offset) +{ + JKRAramStreamCommand* command + = new (JKRGetSystemHeap(), -4) JKRAramStreamCommand(); + command->mType = JKRAramStreamCommand::WRITE; + command->mAddress = addr; + command->mSize = size; + command->mStream = stream; + command->field_0x2c = 0; + command->mOffset = offset; + command->mTransferBuffer = transBuffer; + command->mHeap = transHeap; + command->mTransferBufferSize = transSize; + + OSInitMessageQueue(&command->mMessageQueue, &command->mMessage, 1); + OSSendMessage(&sMessageQueue, command, OS_MESSAGE_BLOCK); + return command; +} + +/* 802B6624-802B66B8 .text sync__13JKRAramStreamFP20JKRAramStreamCommandi + */ +JKRAramStreamCommand* JKRAramStream::sync(JKRAramStreamCommand* command, + int isNonBlocking) +{ + OSMessage message; + if (isNonBlocking == 0) { + OSReceiveMessage(&command->mMessageQueue, &message, OS_MESSAGE_BLOCK); + if (message == nullptr) { + command = nullptr; + return command; + } else { + return command; + } + } else { + BOOL receiveResult = OSReceiveMessage(&command->mMessageQueue, &message, + OS_MESSAGE_NOBLOCK); + if (receiveResult == FALSE) { + command = nullptr; + return command; + } else if (message == nullptr) { + command = nullptr; + return command; + } else { + return command; + } + } +} + +/* 802B66B8-802B6708 .text setTransBuffer__13JKRAramStreamFPUcUlP7JKRHeap + */ +void JKRAramStream::setTransBuffer(u8* buffer, u32 bufferSize, JKRHeap* heap) +{ + transBuffer = nullptr; + transSize = 0x400; + transHeap = nullptr; + + if (buffer) { + transBuffer = (u8*)ALIGN_NEXT((u32)buffer, 0x20); + } + + if (bufferSize) { + transSize = ALIGN_PREV(bufferSize, 0x20); + } + + if (heap && !buffer) { + transHeap = heap; + } +} + +/* 802B6708-802B6714 .text __ct__20JKRAramStreamCommandFv */ +JKRAramStreamCommand::JKRAramStreamCommand() +{ + mAllocatedTransferBuffer = false; +} + +static void dummy(JSURandomInputStream* stream) { stream->getAvailable(); } diff --git a/src/JSystem/JKernel/JKRDecomp.cpp b/src/JSystem/JKernel/JKRDecomp.cpp new file mode 100644 index 00000000..a57f2745 --- /dev/null +++ b/src/JSystem/JKernel/JKRDecomp.cpp @@ -0,0 +1,289 @@ +#include +#include +#include + +JKRDecomp* JKRDecomp::sDecompObject; + +JKRDecomp* JKRDecomp::create(s32 priority) +{ + if (!sDecompObject) { + sDecompObject = new (JKRHeap::getSystemHeap(), 0) JKRDecomp(priority); + } + + return sDecompObject; +} + +OSMessage JKRDecomp::sMessageBuffer[4] = { nullptr }; +OSMessageQueue JKRDecomp::sMessageQueue = { 0 }; + +JKRDecomp::JKRDecomp(s32 priority) + : JKRThread(0x4000, 0x10, priority) +{ + resume(); +} + +JKRDecomp::~JKRDecomp() { } + +void* JKRDecomp::run() +{ + OSInitMessageQueue(&sMessageQueue, sMessageBuffer, 4); + while (true) { + OSMessage message; + OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK); + + JKRDecompCommand* command = (JKRDecompCommand*)message; + decode(command->mSrcBuffer, command->mDstBuffer, command->mSrcLength, + command->mDstLength); + + if (command->field_0x20 != 0) { + if (command->field_0x20 == 1) { + JKRAramPiece::sendCommand(command->mAMCommand); + } + continue; + } + + if (command->mCallback) { + (*command->mCallback)((u32)command); + continue; + } + + if (command->field_0x1c) { + OSSendMessage(command->field_0x1c, (OSMessage)1, + OS_MESSAGE_NOBLOCK); + } else { + OSSendMessage(&command->mMessageQueue, (OSMessage)1, + OS_MESSAGE_NOBLOCK); + } + } +} + +JKRDecompCommand* +JKRDecomp::prepareCommand(u8* srcBuffer, u8* dstBuffer, u32 srcLength, + u32 dstLength, + JKRDecompCommand::AsyncCallback callback) +{ + JKRDecompCommand* command + = new (JKRHeap::getSystemHeap(), -4) JKRDecompCommand(); + command->mSrcBuffer = srcBuffer; + command->mDstBuffer = dstBuffer; + command->mSrcLength = srcLength; + command->mDstLength = dstLength; + command->mCallback = callback; + return command; +} + +void JKRDecomp::sendCommand(JKRDecompCommand* command) +{ + OSSendMessage(&sMessageQueue, command, OS_MESSAGE_BLOCK); +} + +JKRDecompCommand* +JKRDecomp::orderAsync(u8* srcBuffer, u8* dstBuffer, u32 srcLength, + u32 dstLength, JKRDecompCommand::AsyncCallback callback) +{ + JKRDecompCommand* command + = prepareCommand(srcBuffer, dstBuffer, srcLength, dstLength, callback); + sendCommand(command); + return command; +} + +bool JKRDecomp::sync(JKRDecompCommand* command, int isNonBlocking) +{ + OSMessage message; + bool result; + if (isNonBlocking == JKRDECOMP_SYNC_BLOCKING) { + OSReceiveMessage(&command->mMessageQueue, &message, OS_MESSAGE_BLOCK); + result = true; + } else { + result = OSReceiveMessage(&command->mMessageQueue, &message, + OS_MESSAGE_NOBLOCK) + != FALSE; + } + + return result; +} + +bool JKRDecomp::orderSync(u8* srcBuffer, u8* dstBuffer, u32 srcLength, + u32 dstLength) +{ + JKRDecompCommand* command + = orderAsync(srcBuffer, dstBuffer, srcLength, dstLength, nullptr); + bool result = sync(command, JKRDECOMP_SYNC_BLOCKING); + delete command; + return result; +} + +void JKRDecomp::decode(u8* srcBuffer, u8* dstBuffer, u32 srcLength, + u32 dstLength) +{ + JKRCompression compression = checkCompressed(srcBuffer); + if (compression == JKR_COMPRESSION_YAY0) { + decodeSZP(srcBuffer, dstBuffer, srcLength, dstLength); + } else if (compression == JKR_COMPRESSION_YAZ0) { + decodeSZS(srcBuffer, dstBuffer, srcLength, dstLength); + } +} + +void JKRDecomp::decodeSZP(u8* src, u8* dst, u32 srcLength, u32 dstLength) +{ + int srcChunkOffset; + int count; + int dstOffset; + u32 length = srcLength; + int linkInfo; + int offset; + int i; + + int decodedSize = READU32_BE(src, 4); + int linkTableOffset = READU32_BE(src, 8); + int srcDataOffset = READU32_BE(src, 12); + + dstOffset = 0; + u32 counter = 0; + srcChunkOffset = 16; + + u32 chunkBits; + if (srcLength == 0) + return; + if (dstLength > decodedSize) + return; + + do { + if (counter == 0) { + chunkBits = READU32_BE(src, srcChunkOffset); + srcChunkOffset += sizeof(u32); + counter = sizeof(u32) * 8; + } + + if (chunkBits & 0x80000000) { + if (dstLength == 0) { + dst[dstOffset] = src[srcDataOffset]; + length--; + if (length == 0) + return; + } else { + dstLength--; + } + dstOffset++; + srcDataOffset++; + } else { + linkInfo = src[linkTableOffset] << 8 | src[linkTableOffset + 1]; + linkTableOffset += sizeof(u16); + + offset = dstOffset - (linkInfo & 0xFFF); + count = (linkInfo >> 12); + if (count == 0) { + count = (u32)src[srcDataOffset++] + 0x12; + } else + count += 2; + + if (count > decodedSize - dstOffset) + count = decodedSize - dstOffset; + + for (i = 0; i < count; i++, dstOffset++, offset++) { + if (dstLength == 0) { + dst[dstOffset] = dst[offset - 1]; + length--; + if (length == 0) + return; + } else + dstLength--; + } + } + + chunkBits <<= 1; + counter--; + } while (dstOffset < decodedSize); +} + +void JKRDecomp::decodeSZS(u8* src_buffer, u8* dst_buffer, u32 srcSize, + u32 dstSize) +{ + u8* decompEnd; + u8* copyStart; + s32 copyByteCount; + s32 chunkBitsLeft = 0; + s32 chunkBits; + + decompEnd = dst_buffer + *(int*)(src_buffer + 4) - dstSize; + + if (srcSize == 0) { + return; + } + if (dstSize > *(u32*)src_buffer) { + return; + } + + u8* curSrcPos = src_buffer + 0x10; + do { + if (chunkBitsLeft == 0) { + chunkBits = curSrcPos[0]; + chunkBitsLeft = 8; + curSrcPos++; + } + if ((chunkBits & 0x80) != 0) { + if (dstSize == 0) { + dst_buffer[0] = curSrcPos[0]; + srcSize--; + dst_buffer++; + if (srcSize == 0) + return; + } else { + dstSize--; + } + curSrcPos++; + } else { + u32 local_28 = curSrcPos[1] | (curSrcPos[0] & 0xF) << 8; + u32 r31 = curSrcPos[0] >> 4; + curSrcPos += 2; + copyStart = dst_buffer - local_28; + if (r31 == 0) { + copyByteCount = curSrcPos[0] + 0x12; + curSrcPos++; + } else { + copyByteCount = r31 + 2; + } + do { + if (dstSize == 0) { + dst_buffer[0] = copyStart[-1]; + srcSize--; + dst_buffer++; + if (srcSize == 0) + return; + } else { + dstSize--; + } + copyByteCount--; + copyStart++; + } while (copyByteCount != 0); + } + chunkBits <<= 1; + chunkBitsLeft--; + } while (dst_buffer != decompEnd); +} + +JKRCompression JKRDecomp::checkCompressed(u8* src) +{ + if ((src[0] == 'Y') && (src[1] == 'a') && (src[3] == '0')) { + if (src[2] == 'y') { + return JKR_COMPRESSION_YAY0; + } + + if (src[2] == 'z') { + return JKR_COMPRESSION_YAZ0; + } + } + + return JKR_COMPRESSION_NONE; +} + +JKRDecompCommand::JKRDecompCommand() +{ + OSInitMessageQueue(&mMessageQueue, &mMessage, 1); + mCallback = nullptr; + field_0x1c = nullptr; + mThis = this; + field_0x20 = 0; +} + +JKRDecompCommand::~JKRDecompCommand() { } diff --git a/src/JSystem/JKernel/JKRDvdRipper.cpp b/src/JSystem/JKernel/JKRDvdRipper.cpp new file mode 100644 index 00000000..a8ff1569 --- /dev/null +++ b/src/JSystem/JKernel/JKRDvdRipper.cpp @@ -0,0 +1,465 @@ +#include +#include +#include +#include +#include +#include +#include +#include "macros.h" + +static int JKRDecompressFromDVD(JKRDvdFile*, void*, u32, u32, u32, u32); +static int decompSZS_subroutine(u8*, u8*); +static u8* firstSrcData(); +static u8* nextSrcData(u8*); + +/* 802BCD4C-802BCE00 .text + * loadToMainRAM__12JKRDvdRipperFPCcPUc15JKRExpandSwitchUlP7JKRHeapQ212JKRDvdRipper15EAllocDirectionUlPi + */ +void* JKRDvdRipper::loadToMainRAM(const char* name, u8* dst, + JKRExpandSwitch expandSwitch, u32 dstLength, + JKRHeap* heap, EAllocDirection allocDirection, + u32 offset, int* pCompression) +{ + JKRDvdFile file; + if (!file.open(name)) { + return nullptr; + } + return loadToMainRAM(&file, dst, expandSwitch, dstLength, heap, + allocDirection, offset, pCompression); +} + +/* 802BCE00-802BCEB4 .text + * loadToMainRAM__12JKRDvdRipperFlPUc15JKRExpandSwitchUlP7JKRHeapQ212JKRDvdRipper15EAllocDirectionUlPi + */ +void* JKRDvdRipper::loadToMainRAM(s32 entryNumber, u8* dst, + JKRExpandSwitch expandSwitch, u32 dstLength, + JKRHeap* heap, EAllocDirection allocDirection, + u32 offset, int* pCompression) +{ + JKRDvdFile file; + if (!file.open(entryNumber)) { + return nullptr; + } + return loadToMainRAM(&file, dst, expandSwitch, dstLength, heap, + allocDirection, offset, pCompression); +} + +bool JKRDvdRipper::errorRetry = true; + +/* 802BCEB4-802BD324 .text + * loadToMainRAM__12JKRDvdRipperFP10JKRDvdFilePUc15JKRExpandSwitchUlP7JKRHeapQ212JKRDvdRipper15EAllocDirectionUlPi + */ +void* JKRDvdRipper::loadToMainRAM(JKRDvdFile* dvdFile, u8* dst, + JKRExpandSwitch expandSwitch, u32 dstLength, + JKRHeap* heap, EAllocDirection allocDirection, + u32 offset, int* pCompression) +{ + s32 fileSizeAligned; + bool hasAllocated = false; + JKRCompression compression = JKR_COMPRESSION_NONE; + u32 expandSize; + u8* mem = nullptr; + + fileSizeAligned = ALIGN_NEXT(dvdFile->getFileSize(), 32); + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS) { + u8 buffer[0x40]; + u8* bufPtr = (u8*)ALIGN_NEXT((u32)buffer, 32); + while (true) { + int readBytes + = DVDReadPrio(dvdFile->getFileInfo(), bufPtr, 0x20, 0, 2); + if (readBytes >= 0) { + break; + } + + if (readBytes == -3 || !isErrorRetry()) { + return nullptr; + } + + VIWaitForRetrace(); + } + DCInvalidateRange(bufPtr, 0x20); + + compression = JKRCheckCompressed(bufPtr); + expandSize = JKRDecompExpandSize(bufPtr); + } + + if (pCompression) { + *pCompression = (int)compression; + } + + if (expandSwitch == EXPAND_SWITCH_DECOMPRESS + && compression != JKR_COMPRESSION_NONE) { + if (dstLength != 0 && expandSize > dstLength) { + expandSize = dstLength; + } + if (dst == nullptr) { + dst = (u8*)JKRAllocFromHeap( + heap, expandSize, + allocDirection == ALLOC_DIRECTION_FORWARD ? 32 : -32); + hasAllocated = true; + } + if (dst == nullptr) { + return nullptr; + } + if (compression == JKR_COMPRESSION_YAY0) { + mem = (u8*)JKRAllocFromHeap((heap), fileSizeAligned, 32); + if (mem == nullptr) { + if (hasAllocated == true) { + JKRFree(dst); + return nullptr; + } + } + } + } else { + if (dst == nullptr) { + dst = (u8*)JKRAllocFromHeap( + heap, fileSizeAligned - offset, + allocDirection == ALLOC_DIRECTION_FORWARD ? 32 : -32); + hasAllocated = true; + } + if (dst == nullptr) { + return nullptr; + } + } + if (compression == JKR_COMPRESSION_NONE) { + JKRCompression compression2 + = JKR_COMPRESSION_NONE; // maybe for a sub archive? + + if (offset != 0) { + u8 buffer[0x40]; + u8* bufPtr = (u8*)ALIGN_NEXT((u32)buffer, 32); + while (true) { + int readBytes = DVDReadPrio(dvdFile->getFileInfo(), bufPtr, 32, + (s32)offset, 2); + if (readBytes >= 0) { + break; + } + + if (readBytes == -3 || !isErrorRetry()) { + if (hasAllocated == true) { + JKRFree(dst); + } + return nullptr; + } + VIWaitForRetrace(); + } + DCInvalidateRange(bufPtr, 32); + + compression2 = JKRCheckCompressed(bufPtr); + } + if ((compression2 == JKR_COMPRESSION_NONE + || expandSwitch == EXPAND_SWITCH_NONE) + || expandSwitch == EXPAND_SWITCH_DEFAULT) { + s32 size = fileSizeAligned - offset; + if (dstLength != 0 && dstLength < size) + size = dstLength; // probably a ternary + while (true) { + int readBytes = DVDReadPrio(dvdFile->getFileInfo(), dst, size, + (s32)offset, 2); + if (readBytes >= 0) { + break; + } + + if (readBytes == -3 || !isErrorRetry()) { + if (hasAllocated == true) { + JKRFree(dst); + } + return nullptr; + } + VIWaitForRetrace(); + } + + return dst; + } else if (compression2 == JKR_COMPRESSION_YAZ0) { + JKRDecompressFromDVD(dvdFile, dst, fileSizeAligned, dstLength, 0, + offset); + } else { + OSPanic(__FILE__, 337, "Sorry, not prepared for SZP resource\n"); + } + return dst; + } else if (compression == JKR_COMPRESSION_YAY0) { + // SZP decompression + // s32 readoffset = startOffset; + if (offset != 0) { + OSPanic(__FILE__, 347, ":::Not support SZP with offset read"); + } + while (true) { + int readBytes = DVDReadPrio(dvdFile->getFileInfo(), mem, + fileSizeAligned, 0, 2); + if (readBytes >= 0) + break; + + if (readBytes == -3 || !isErrorRetry()) { + if (hasAllocated == true) + JKRFree(dst); + + JKRFree(mem); + return nullptr; + } + VIWaitForRetrace(); + } + JKRDecompress(mem, dst, expandSize, offset); + JKRFree(mem); + return dst; + } else if (compression == JKR_COMPRESSION_YAZ0) { + if (JKRDecompressFromDVD(dvdFile, dst, fileSizeAligned, expandSize, + offset, 0) + != 0u) { + if (hasAllocated) + JKRFree(dst); + dst = nullptr; + } + return dst; + } else if (hasAllocated) { + JKRFree(dst); + dst = nullptr; + } + return nullptr; +} + +JSUList JKRDvdRipper::sDvdAsyncList; +static OSMutex decompMutex; +u32 JKRDvdRipper::szpBufferSize = 0x00000400; +static u8* szpBuf; +static u8* szpEnd; +static u8* refBuf; +static u8* refEnd; +static u8* refCurrent; +static u32 srcOffset; +static u32 transLeft; +static u8* srcLimit; +static JKRDvdFile* srcFile; +static u32 fileOffset; +static u32 readCount; +static u32 maxDest; +static bool isInitMutex; + +/* 802BD324-802BD4F0 .text JKRDecompressFromDVD__FP10JKRDvdFilePvUlUlUlUl + */ +static int JKRDecompressFromDVD(JKRDvdFile* dvdFile, void* dst, u32 fileSize, + u32 inMaxDest, u32 inFileOffset, + u32 inSrcOffset) +{ + BOOL interrupts = OSDisableInterrupts(); + if (isInitMutex == false) { + OSInitMutex(&decompMutex); + isInitMutex = true; + } + OSRestoreInterrupts(interrupts); + OSLockMutex(&decompMutex); + int bufSize = JKRDvdRipper::getSzpBufferSize(); + szpBuf = (u8*)JKRAllocFromSysHeap(bufSize, -0x20); + JUT_ASSERT(VERSION_SELECT(913, 884, 884), szpBuf != nullptr); + + szpEnd = szpBuf + bufSize; + if (inFileOffset != 0) { + refBuf = (u8*)JKRAllocFromSysHeap(0x1120, -4); + JUT_ASSERT(VERSION_SELECT(922, 893, 893), refBuf != nullptr); + refEnd = refBuf + 0x1120; + refCurrent = refBuf; + } else { + refBuf = nullptr; + } + srcFile = dvdFile; + srcOffset = inSrcOffset; + transLeft = fileSize - inSrcOffset; + fileOffset = inFileOffset; + readCount = 0; + maxDest = inMaxDest; + u8* data = firstSrcData(); + u32 result = (data != nullptr) ? decompSZS_subroutine(data, (u8*)dst) + : -1; // figure out correct datatypes + u32 decompressedSize = ((u32*)data)[1]; + JKRFree(szpBuf); + if (refBuf) { + JKRFree(refBuf); + } + DCStoreRangeNoSync(dst, decompressedSize); + OSUnlockMutex(&decompMutex); + return result; +} + +/* 802BD4F0-802BD784 .text decompSZS_subroutine__FPUcPUc */ +static int decompSZS_subroutine(u8* src, u8* dest) +{ + u8* endPtr; + s32 validBitCount = 0; + s32 currCodeByte = 0; + u32 ts = 0; + + if (src[0] != 'Y' || src[1] != 'a' || src[2] != 'z' || src[3] != '0') { + return -1; + } + + SYaz0Header* header = (SYaz0Header*)src; + endPtr = dest + (header->length - fileOffset); + if (endPtr > dest + maxDest) { + endPtr = dest + maxDest; + } + + src += 0x10; + do { + if (validBitCount == 0) { + if ((src > srcLimit) && transLeft) { + src = nextSrcData(src); + if (!src) { + return -1; + } + } + currCodeByte = *src; + validBitCount = 8; + src++; + } + if (currCodeByte & 0x80) { + if (fileOffset != 0) { + if (readCount >= fileOffset) { + *dest = *src; + dest++; + ts++; + if (dest == endPtr) { + break; + } + } + *(refCurrent++) = *src; + if (refCurrent == refEnd) { + refCurrent = refBuf; + } + src++; + } else { + *dest = *src; + dest++; + src++; + ts++; + if (dest == endPtr) { + break; + } + } + readCount++; + } else { + u32 dist = ((src[0] & 0x0f) << 8) | src[1]; + s32 numBytes = src[0] >> 4; + src += 2; + u8* copySource; + if (fileOffset != 0) { + copySource = refCurrent - dist - 1; + if (copySource < refBuf) { + copySource += refEnd - refBuf; + } + } else { + copySource = dest - dist - 1; + } + if (numBytes == 0) { + numBytes = *src + 0x12; + src += 1; + } else { + numBytes += 2; + } + if (fileOffset != 0) { + do { + if (readCount >= fileOffset) { + *dest = *copySource; + dest++; + ts++; + if (dest == endPtr) { + break; + } + } + *(refCurrent++) = *copySource; + if (refCurrent == refEnd) { + refCurrent = refBuf; + } + copySource++; + if (copySource == refEnd) { + copySource = refBuf; + } + readCount++; + numBytes--; + } while (numBytes != 0); + } else { + do { + *dest = *copySource; + dest++; + ts++; + if (dest == endPtr) { + break; + } + readCount++; + numBytes--; + copySource++; + } while (numBytes != 0); + } + } + currCodeByte <<= 1; + validBitCount--; + } while (dest < endPtr); + return 0; +} + +/* 802BD784-802BD84C .text firstSrcData__Fv */ +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->getFileInfo(), buffer, length, srcOffset, 2); + if (result >= 0) { + break; + } + + if (result == -3 || !JKRDvdRipper::isErrorRetry()) { + return nullptr; + } + VIWaitForRetrace(); + } + + srcOffset += length; + transLeft -= length; + if (transLeft == 0) { + srcLimit = buffer + length; + } + return buffer; +} + +/* 802BD84C-802BD974 .text nextSrcData__FPUc */ +static u8* nextSrcData(u8* src) +{ + u32 limit = szpEnd - src; + u8* buf; + if (IS_NOT_ALIGNED(limit, 0x20)) { + buf = szpBuf + 0x20 - (limit & (0x20 - 1)); + } else { + buf = szpBuf; + } + + memcpy(buf, src, limit); + u32 transSize = (u32)(szpEnd - (buf + limit)); + if (transSize > transLeft) { + transSize = transLeft; + } + JUT_ASSERT(VERSION_SELECT(1228, 1176, 1176), transSize > 0); + + while (true) { + s32 result = DVDReadPrio(srcFile->getFileInfo(), (buf + limit), + transSize, srcOffset, 2); + if (result >= 0) { + break; + } + // bug: supposed to call isErrorRetry, but didn't + if (result == -3 || !JKRDvdRipper::isErrorRetry) { + return nullptr; + } + + VIWaitForRetrace(); + } + srcOffset += transSize; + transLeft -= transSize; + if (transLeft == 0) { + srcLimit = transSize + (buf + limit); + } + + return buf; +}