JKRDvdRipper WIP

This commit is contained in:
SwareJonge 2023-01-27 03:32:06 +01:00
parent 4174a13849
commit cf57db4754
8 changed files with 551 additions and 34 deletions

View File

@ -51,6 +51,18 @@ JSystem/JKernel/JKRDvdFile.cpp:
#.bss: [0x803fa944, 0x803fa950]
.sdata2: [0x80417a68, 0x80417a78]
#JSystem/JKernel/JKRDvdRipper.cpp:
#.text: [0x80080e68, 0x80081bcc]
#.ctors: [0x803160e4, 0x803160e8]
#.rodata: [0x80366c20, 0x80366ca8]
#.bss: [0x803ae988, 0x803ae9b0]
#.bss [0x803fa95c, 0x803fa968] # common bss, my favourite!
#.sdata: [0x80414088, 0x80414090]
#.sbss: [0x80415948, 0x80415988]
#.sdata2: [0x80417aa0, 0x80417ab0]
Dolphin/__ppc_eabi_init.s:
.text: [0x800f31d8, 0x800f322c]

View File

@ -370,6 +370,17 @@ global:
0x8038b2e0: __vt__10JKRDvdFile
0x803fa944: sDvdList__10JKRDvdFile
# JKRDvdRipper.cpp
0x80080e68: loadToMainRAM__12JKRDvdRipperFPCcPUc15JKRExpandSwitchUlP7JKRHeapQ212JKRDvdRipper15EAllocDirectionUlPiPUl
0x80080f1c: loadToMainRAM__12JKRDvdRipperFlPUc15JKRExpandSwitchUlP7JKRHeapQ212JKRDvdRipper15EAllocDirectionUlPiPUl
0x80080fd0: loadToMainRAM__12JKRDvdRipperFP10JKRDvdFilePUc15JKRExpandSwitchUlP7JKRHeapQ212JKRDvdRipper15EAllocDirectionUlPiPUl
0x8008149c: JKRDecompressFromDVD__FP10JKRDvdFilePvUlUlUlUlPUl
0x80081b34: isErrorRetry__12JKRDvdRipperFv
0x80081b80: __dt__23JSUList<12JKRDMCommand>Fv
0x803fa95c: sDvdAsyncList__12JKRDvdRipper
0x80414088: errorRetry__12JKRDvdRipper
0x8041408c: sSZSBufferSize__12JKRDvdRipper
# JKRExpHeap.cpp
0x80081c4c: create__10JKRExpHeapFUlP7JKRHeapb
0x80081d18: create__10JKRExpHeapFPvUlP7JKRHeapb
@ -500,6 +511,7 @@ global:
0x800b1908: DVDOpen
0x800b19d0: DVDClose
0x800b1c18: DVDReadAsyncPrio
0x800b1d08: DVDReadPrio
0x800b1e48: DVDInit
0x800b3e80: DVDGetCommandBlockStatus
@ -707,7 +719,24 @@ global:
0x800ed154: OSCancelAlarm
# OSCache.c
0x800eda58: DCEnable
0x800eda6c: DCInvalidateRange
0x800eda98: DCFlushRange
0x800edac8: DCStoreRange
0x800edaf8: DCFlushRangeNoSync
0x800edb24: DCStoreRangeNoSync
0x800edb50: DCZeroRange
0x800edb7c: ICInvalidateRange
0x800edbb0: ICFlashInvalidate
0x800edbc0: ICEnable
0x800edca0: LCEnable
0x800edcd8: LCDisable
0x800edd00: LCStoreBlocks
0x800edd24: LCStoreData
0x800eddd0: LCQueueWait
0x800edde4: L2GlobalInvalidate
0x800ede7c: DMAErrorHandler
0x800edfdc: __OSCacheInit
# OSError.c
0x800eea6c: OSReport

17
expected.py Normal file
View File

@ -0,0 +1,17 @@
"""
Creates the expected folder for diff.py
"""
from shutil import copytree, rmtree
import common as c
# Remove it if already existing
try:
rmtree(c.EXPECTED)
except FileNotFoundError:
pass
# Copy in builddir and outdir
copytree(c.BUILDDIR, f"{c.EXPECTED}/build")
copytree(c.OUTDIR, f"{c.EXPECTED}/out")

View File

@ -10,11 +10,6 @@ class SArcDataInfo;
class SDirEntry;
class SDIFileEntry;
inline u16 read_big_endian_u16(void *ptr) {
u8 *uptr = (u8 *)ptr;
return ((u16)uptr[0] << 8) | ((u16)uptr[1]);
}
inline u32 read_big_endian_u32(void *ptr) {
u8 *uptr = (u8 *)ptr;
return ((u32)uptr[0] << 0x18) | ((u32)uptr[1] << 0x10) | ((u32)uptr[2] << 8) | (u32)uptr[3];

View File

@ -13,6 +13,13 @@ enum JKRExpandSwitch
Switch_1,
Switch_2
};
struct SYaz0Header
{
u32 signature;
u32 length;
};
class JKRDvdFile;
class JKRDMCommand {
@ -21,10 +28,12 @@ class JKRDMCommand {
};
namespace JKRDvdRipper { // not sure if this is a class/struct or a namespace(if it is a class, it could be inherited from JKRRipper perhaps?)
enum EAllocDirection { // Placeholder
DIRECTION_0,
DIRECTION_1,
DIRECTION_2,
enum EAllocDirection {
ALLOC_DIR_PAD, // Unseen/unhandled so far
ALLOC_DIR_TOP, //!< [1] Negative alignment; allocate block from top of
//!< free block.
ALLOC_DIR_BOTTOM, //!< [2] Positive alignment; allocate block from
//!< bottom of free block.
};
// could also be u8 * return, however most functions seem to use void *
void * loadToMainRAM(const char *, u8 *, JKRExpandSwitch, u32, JKRHeap *, EAllocDirection, u32, int *, u32 *);
@ -43,11 +52,11 @@ namespace JKRDvdRipper { // not sure if this is a class/struct or a namespace(if
// these both exist too JKRAramRipper? copy paste or is something else going on? i'm guessing copy paste
extern bool errorRetry;
extern s32 sSZSBufferSize; // 0x400
extern const s32 sSZSBufferSize; // 0x400
// Weak
bool isErrorRetry() { return errorRetry; } // this is unused but for whatever reason it gets linked
inline bool isErrorRetry() { return errorRetry; } // this is unused but for whatever reason it gets linked
}
void JKRDecompressFromDVD(JKRDvdFile *, void *, u32, u32, u32, u32, u32);
int JKRDecompressFromDVD(JKRDvdFile *, void *, u32, u32, u32, u32, u32 *);
#endif

View File

@ -35,4 +35,17 @@ typedef int unknown;
#define nullptr 0
#define null 0
// Get the maximum of two values
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
// Get the minimum of two values
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
// Align X to the previous N bytes (N must be power of two)
#define ALIGN_PREV(X, N) ((X) & ~((N)-1))
// Align X to the next N bytes (N must be power of two)
#define ALIGN_NEXT(X, N) ALIGN_PREV(((X) + (N)-1), N)
#define IS_ALIGNED(X, N)(((X) & ((N)-1)) == 0)
#define IS_NOT_ALIGNED(X, N) (((X) & ((N)-1)) != 0)
#endif // !TYPES_H

View File

@ -92,7 +92,7 @@ bool JKRDecomp::sync(JKRDecompCommand *command, int isNonBlocking) {
}
bool JKRDecomp::orderSync(u8 *srcBuffer, u8 *dstBuffer, u32 srcLength, u32 dstLength) {
JKRDecompCommand *command = orderAsync(srcBuffer, dstBuffer, srcLength, dstLength, NULL);
JKRDecompCommand *command = orderAsync(srcBuffer, dstBuffer, srcLength, dstLength, nullptr);
bool result = sync(command, JKRDECOMP_SYNC_BLOCKING);
delete command;
return result;

View File

@ -1,42 +1,484 @@
#include "dolphin/OS.h"
#include "dolphin/stl.h"
#include "dolphin/vi.h"
#include "JSystem/JKernel/JKRArchive.h"
#include "JSystem/JKernel/JKRDecomp.h"
#include "JSystem/JKernel/JKRHeap.h"
#include "JSystem/JUtility/JUTDbg.h"
#include "JSystem/JKernel/JKRDvdRipper.h"
// WIP, missing classes
// WIP, not matching
u8 *firstSrcData();
u8 *nextSrcData(u8*);
int decompSZS_subroutine(unsigned char *, unsigned char *);
static OSMutex decompMutex;
static u8 *szpBuf;
static u8 *szpEnd;
static u8 *refBuf;
static u8 *refEnd;
static u8 *refCurrent;
static u32 srcOffset;
static long transLeft;
static u8 *srcLimit;
static JKRDvdFile *srcFile;
static u32 fileOffset;
static u32 readCount;
static u32 maxDest;
static bool isInitMutex;
static u32 *tsPtr;
static u32 tsArea;
JSUList<JKRDMCommand> JKRDvdRipper::sDvdAsyncList;
namespace JKRDvdRipper {
bool errorRetry;
const s32 sSZSBufferSize = 0x400;
void *loadToMainRAM(const char *fileName, u8 *ptr, JKRExpandSwitch expSwitch, u32 p4, JKRHeap *heap, EAllocDirection allocDirection, u32 p7, int *p8, u32 *p9) {
void * file;
void *loadToMainRAM(const char *fileName, u8 *ptr, JKRExpandSwitch expSwitch, u32 p4, JKRHeap *heap, EAllocDirection allocDirection, u32 startOffset, int *pCompression, u32 *p9) {
JKRDvdFile dvdFile;
if (dvdFile.open(fileName)) {
file = loadToMainRAM(&dvdFile, ptr, expSwitch, p4, heap, allocDirection, p7, p8, p9);
delete &dvdFile;
if (!dvdFile.open(fileName)) {
return nullptr;
}
else {
delete &dvdFile;
file = nullptr;
return loadToMainRAM(&dvdFile, ptr, expSwitch, p4, heap, allocDirection, startOffset, pCompression, p9);
}
}
void *loadToMainRAM(s32 entryNum, u8 *ptr, JKRExpandSwitch expSwitch, u32 p4, JKRHeap *heap, EAllocDirection allocDirection, u32 startOffset, int *pCompression, u32 *p9) {
JKRDvdFile dvdFile;
if (!dvdFile.open(entryNum)) {
return nullptr;
}
else {
return loadToMainRAM(&dvdFile, ptr, expSwitch, p4, heap, allocDirection, startOffset, pCompression, p9);
}
}
// Not matching, huge size mismatch
void *loadToMainRAM(JKRDvdFile * jkrDvdFile, u8 * file, JKRExpandSwitch expandSwitch, u32 fileSize, JKRHeap * heap, EAllocDirection allocDirection, u32 startOffset, int * pCompression, u32 *p9) {
bool hasAllocated = false;
CompressionMethod compression = TYPE_NONE;
u8 * mem = nullptr;
u32 fileSizeAligned = ALIGN_NEXT(jkrDvdFile->getFileSize(), 32);
u32 uncompressedSize; // investigate, could also be compressed Size
if (expandSwitch == Switch_1)
{
u8 buffer[0x40];
u8 *bufPtr = (u8 *)ALIGN_NEXT((u32)buffer, 0x20);
while(true) {
int readBytes = DVDReadPrio(&jkrDvdFile->mDvdFileInfo, bufPtr, 0x20, 0, 2);
if (readBytes >= 0)
break;
if (readBytes == -3 || errorRetry == 0) {
return nullptr;
}
VIWaitForRetrace();
}
DCInvalidateRange(bufPtr, 0x20);
compression = JKRDecomp::checkCompressed(bufPtr);
if (compression == TYPE_ASR) {
compression = TYPE_NONE;
}
uncompressedSize = read_big_endian_u32(buffer + 4);
}
if(pCompression)
*pCompression = (int)compression;
if(expandSwitch == Switch_1 && compression != TYPE_NONE) {
if (fileSize != 0 && fileSize < uncompressedSize) {
uncompressedSize = fileSize;
}
if(file == nullptr) {
file = (u8 *)JKRHeap::alloc(uncompressedSize, allocDirection == ALLOC_DIR_TOP ? 32 : -32, heap);
hasAllocated = true;
if(file == nullptr) {
return nullptr;
}
if (compression == TYPE_YAY0) {
mem = (u8*)JKRHeap::alloc(uncompressedSize, 32, heap);
if (mem == nullptr && hasAllocated) {
JKRHeap::free(file, nullptr);
return nullptr;
}
}
}
else {
if(file == nullptr) {
u32 size = uncompressedSize - startOffset;
if(fileSize != 0 && fileSize < size)
size = fileSize; // probably a ternary
file = (u8 *)JKRHeap::alloc(uncompressedSize, allocDirection == ALLOC_DIR_TOP ? 32 : -32, heap);
hasAllocated = true;
}
if(file == nullptr)
return nullptr;
}
}
if(compression == TYPE_NONE) {
int readBytes = 0;
if(fileSize != 0) {
u8 buffer[0x40]; // maybe create struct
u8 *bufPtr = (u8 *)ALIGN_NEXT((u32)buffer, 32);
while (true)
{
readBytes = DVDReadPrio(&jkrDvdFile->mDvdFileInfo, buffer, 32, 0, 2);
if (readBytes >= 0)
break;
if (readBytes == -3 || errorRetry == 0) {
return nullptr;
}
VIWaitForRetrace();
}
DCInvalidateRange(buffer, 32);
compression = JKRDecomp::checkCompressed(buffer);
if (compression == TYPE_ASR) {
compression = TYPE_NONE; // Wtf?
}
}
if (compression == 0 || expandSwitch == Switch_2 || expandSwitch == Switch_0)
{
u32 size = uncompressedSize - startOffset;
if (fileSize != 0 && fileSize < size)
size = fileSize; // probably a ternary
while (true)
{
readBytes = DVDReadPrio(&jkrDvdFile->mDvdFileInfo, file, size, startOffset, 2);
if (readBytes >= 0)
break;
if (readBytes == -3 || errorRetry == 0)
{
if (hasAllocated)
JKRHeap::free(file, nullptr);
return nullptr;
}
VIWaitForRetrace();
}
}
else if (compression == TYPE_YAZ0) {
JKRDecompressFromDVD(jkrDvdFile, file, uncompressedSize, fileSize, 0, startOffset, p9);
}
else {
JUT_PANIC(323, "Sorry, not applied for SZP archive.");
}
}
else if(compression == TYPE_YAY0) {
if(startOffset != 0)
JUT_PANIC(333, "Not support SZP with offset read");
while (true)
{
int readBytes = DVDReadPrio(&jkrDvdFile->mDvdFileInfo, mem, uncompressedSize, 0, 2);
if (readBytes >= 0)
break;
if (readBytes == -3 || errorRetry == 0)
{
if (hasAllocated)
JKRHeap::free(file, nullptr);
JKRHeap::free(mem, nullptr);
return nullptr;
}
VIWaitForRetrace();
}
DCInvalidateRange(mem, fileSizeAligned);
JKRDecomp::orderSync(mem, file, uncompressedSize, startOffset);
JKRHeap::free(mem, nullptr);
if(p9) {
*p9 = uncompressedSize;
}
return file;
}
else if(compression == TYPE_YAY0) {
if (JKRDecompressFromDVD(jkrDvdFile, file, fileSizeAligned, uncompressedSize, startOffset, 0, p9)) {
if(hasAllocated)
JKRHeap::free(file, nullptr);
void *loadToMainRAM(s32 entryNum, u8 *ptr, JKRExpandSwitch expSwitch, u32 p4, JKRHeap *heap, EAllocDirection allocDirection, u32 p7, int *p8, u32 *p9) {
void * file;
JKRDvdFile dvdFile;
if (dvdFile.open(entryNum)) {
file = loadToMainRAM(&dvdFile, ptr, expSwitch, p4, heap, allocDirection, p7, p8, p9);
delete &dvdFile;
}
else {
delete &dvdFile;
file = nullptr;
}
return file;
}
else {
if (hasAllocated)
JKRHeap::free(file, nullptr);
void *loadToMainRAM(JKRDvdFile * jkrDvdFile, u8 * file, JKRExpandSwitch expandSwitch, u32 p4, JKRHeap * heap, EAllocDirection allocDirection, u32 p7, int * p8, u32 *p9) {
if (expandSwitch == Switch_1) {
DVDReadPrio(&jkrDvdFile->mDvdFileInfo, , 0x20, 0, 2);
file = nullptr;
}
return file;
}
}
// doesn't match
int JKRDecompressFromDVD(JKRDvdFile *file, void *p2, unsigned long p3, unsigned long inMaxDest, unsigned long inFileOffset,
unsigned long inSrcOffset, unsigned long *inTsPtr)
{
int interrupts = OSDisableInterrupts();
if (isInitMutex == false)
{
OSInitMutex(&decompMutex);
isInitMutex = true;
}
OSRestoreInterrupts(interrupts);
OSLockMutex(&decompMutex);
szpBuf = (u8 *)JKRHeap::sSystemHeap->alloc(JKRDvdRipper::sSZSBufferSize, -0x20);
szpEnd = szpBuf + JKRDvdRipper::sSZSBufferSize;
if (inFileOffset != 0)
{
refBuf = (u8 *)JKRHeap::sSystemHeap->alloc(0x1120, -4);
refEnd = refBuf + 0x1120;
refCurrent = refBuf;
}
else
{
refBuf = nullptr;
}
transLeft = p3 - inSrcOffset;
readCount = 0;
if (inTsPtr == 0)
{
inTsPtr = &tsArea;
}
srcOffset = inSrcOffset;
srcFile = file;
fileOffset = inFileOffset;
maxDest = inMaxDest;
tsPtr = inTsPtr;
*inTsPtr = 0;
u8 *data = firstSrcData();
int result = (data != nullptr) ? decompSZS_subroutine(data, (u8 *)p2) : -1;
JKRHeap::free(szpBuf, nullptr);
if (refBuf)
{
JKRHeap::free(refBuf, nullptr);
}
DCStoreRangeNoSync(p2, *tsPtr);
OSUnlockMutex(&decompMutex);
return result;
}
// Might match, however i expect regswaps here
int decompSZS_subroutine(u8 *src, u8 *dest)
{
int validBitCount = 0;
u32 currCodeByte = 0;
u32 ts = 0;
if (src[0] != 'Y' || src[1] != 'a' || src[2] != 'z' || src[3] != '0')
{
return -1;
}
SYaz0Header *header = (SYaz0Header *)src;
u8 *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);
*tsPtr = ts;
return 0;
}
// doesn't match, target = 0xC4 current: 0xBC(maybe try different build flags)
u8 *firstSrcData()
{
srcLimit = szpEnd - 0x19;
u32 byteCount = MIN(transLeft, (u32)(szpEnd - szpBuf));
// u32 byteCount;
// if (transLeft < byteCount) {
// byteCount = transLeft;
// }
while (true)
{
int result = DVDReadPrio(&srcFile->mDvdFileInfo, szpBuf, byteCount, srcOffset, 2);
if (0 <= result)
{
break;
}
if (result == -3 || !JKRDvdRipper::isErrorRetry())
{
return nullptr;
}
VIWaitForRetrace();
}
DCInvalidateRange(szpBuf, byteCount);
srcOffset += byteCount;
transLeft -= byteCount;
return szpBuf;
}
// Target: 0x138 Current: 0xF4
u8 *nextSrcData(u8 *param_0)
{
u32 size = szpEnd - param_0;
u8 *dest = IS_NOT_ALIGNED(size, 0x20) ? szpBuf + 0x20 - (size & (0x20 - 1)) : szpBuf;
memcpy(dest, param_0, size);
u8 *end = dest + size;
u32 transSize = szpEnd - end;
if (transSize > transLeft)
{
transSize = transLeft;
}
while (true)
{
s32 result = DVDReadPrio(&srcFile->mDvdFileInfo, end, transSize, srcOffset, 2);
if (result >= 0)
{
break;
}
// bug: supposed to call isErrorRetry, but didn't
if (result == -3 || !JKRDvdRipper::isErrorRetry)
{
return NULL;
}
VIWaitForRetrace();
}
DCInvalidateRange(end, transSize);
srcOffset += transSize;
transLeft -= transSize;
if (transLeft == 0)
{
srcLimit = end + transSize;
}
return dest;
}