diosmios/DVD.c
crediar@rypp.net 6daa97aaaf *Added the FatFS link map feature which should greatly decrease load times
git-svn-id: svn://localhost/Users/andi/Downloads/code/DML@41 be6c1b03-d731-4111-a574-e37d80d43941
2014-07-02 08:34:53 +00:00

383 lines
8.4 KiB
C

#include "DVD.h"
DVDConfig *DICfg = (DVDConfig *)NULL;
u32 read;
static char GamePath[256];
extern FIL GameFile;
extern u32 FSTMode;
static u8 *FSTable ALIGNED(32);
u32 ApploaderSize = 0;
u32 dolOffset = 0;
u32 FSTableSize = 0;
u32 FSTableOffset = 0;
u32 FCEntry=0;
FileCache FC[FILECACHE_MAX];
u32 FCState[FILECACHE_MAX];
DWORD LTable[1024];
static void DVDCreateLinkMap( FIL *File )
{
GameFile.cltbl = LTable;
GameFile.cltbl[0] = sizeof(LTable);
s32 fres = f_lseek( &GameFile, CREATE_LINKMAP );
if( fres == FR_NOT_ENOUGH_CORE )
{
GameFile.cltbl = NULL;
}
}
s32 DVDSelectGame( void )
{
char *str = (char*)malloca( 256, 32 );
u32 i=0;
if( ConfigGetConfig(DML_CFG_GAME_PATH) )
{
sprintf( str, "%s", ConfigGetGamePath() );
} else {
dbgprintf("DIP:No game path was supplied!\n");
free(str);
return -1;
}
s32 fres = f_open( &GameFile, str, FA_READ );
if( fres != FR_OK )
{
sprintf( GamePath, "%s", str );
//Try to switch to FST mode
if( !FSTInit() )
{
dbgprintf("DIP:Failed to open:\"%s\" fres:%d\n", str, fres );
free(str);
return -2;
}
} else {
f_close( &GameFile );
dbgprintf("DIP:Current Gamepath:\"%s\"\n", str );
//search the string backwards for '/'
for( i=strlen(str); i > 0; --i )
if( str[i] == '/' )
break;
i++;
if( ConfigGetConfig(DML_CFG_BOOT_DISC2) )
{
sprintf( str+i, "disc2.iso" );
} else {
sprintf( str+i, "game.iso" );
}
dbgprintf("DIP:New Gamepath:\"%s\"\n", str );
fres = f_open( &GameFile, str, FA_READ );
if( fres != FR_OK )
{
dbgprintf("DIP:Failed to open:\"%s\" fres:%d\n", str, fres );
free(str);
return -3;
}
DVDCreateLinkMap(&GameFile);
f_lseek( &GameFile, 0 );
f_read( &GameFile, (void*)0, 0x20, &read );
f_lseek( &GameFile, 0 );
f_read( &GameFile, str, 0x400, &read );
dbgprintf("DIP:Loading game %.6s: %s\n", str, (char *)(str+0x20));
f_lseek( &GameFile, 0x420 );
f_read( &GameFile, str, 0x40, &read );
}
free( str );
return DI_SUCCESS;
}
u32 FSTInit( void )
{
char Path[256];
FIL fd;
u32 read;
sprintf( Path, "%ssys/boot.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return 0;
} else {
u8 *rbuf = (u8*)malloc( 0x100 );
f_lseek( &fd, 0 );
f_read( &fd, rbuf, 0x100, &read );
dbgprintf("DIP:Loading game %.6s: %s\n", rbuf, (char *)(rbuf+0x20));
//Read DOL/FST offset/sizes for later usage
f_lseek( &fd, 0x0420 );
f_read( &fd, rbuf, 0x20, &read );
dolOffset = *(u32*)(rbuf);
FSTableOffset = *(u32*)(rbuf+4);
FSTableSize = *(u32*)(rbuf+8);
free( rbuf );
dbgprintf( "DIP:FSTableOffset:%08X\n", FSTableOffset );
dbgprintf( "DIP:FSTableSize: %08X\n", FSTableSize );
dbgprintf( "DIP:DolOffset: %08X\n", dolOffset );
FSTMode = 1;
f_close( &fd );
}
//Init cache
u32 count = 0;
for( count=0; count < FILECACHE_MAX; ++count )
{
FCState[count] = 0xdeadbeef;
}
return 1;
}
void Asciify( char *str )
{
int i=0;
for( i=0; i < strlen(str); i++ )
if( str[i] < 0x20 || str[i] > 0x7F )
str[i] = '_';
}
void FSTRead( char *Buffer, u32 Length, u32 Offset )
{
char Path[256];
FIL fd;
u32 read;
int i,j;
if( Offset >= FSTableOffset+FSTableSize ) {
//Get FSTTable offset from low memory, must be set by apploader
if( FSTable == NULL )
{
FSTable = (u8*)((*(vu32*)0x38) & 0x7FFFFFFF);
//dbgprintf("DIP:FSTOffset: %08X\n", (u32)FSTable );
}
//try cache first!
for( i=0; i < FILECACHE_MAX; ++i )
{
if( FCState[i] == 0xdeadbeef )
continue;
if( Offset >= FC[i].Offset )
{
u64 nOffset = Offset - FC[i].Offset;
if( nOffset < FC[i].Size )
{
//dbgprintf("DIP:[Cache:%02d][%08X:%05X]\n", i, (u32)(nOffset>>2), Length );
f_lseek( &(FC[i].File), nOffset );
f_read( &(FC[i].File), Buffer, ((Length)+31)&(~31), &read );
return;
}
}
}
//The fun part!
u32 Entries = *(u32*)(FSTable+0x08);
char *NameOff = (char*)(FSTable + Entries * 0x0C);
FEntry *fe = (FEntry*)(FSTable);
u32 Entry[16];
u32 LEntry[16];
u32 level=0;
for( i=1; i < Entries; ++i )
{
if( level )
{
while( LEntry[level-1] == i )
{
//printf("[%03X]leaving :\"%s\" Level:%d\n", i, buffer + NameOff + swap24( fe[Entry[level-1]].NameOffset ), level );
level--;
}
}
if( fe[i].Type )
{
//Skip empty folders
if( fe[i].NextOffset == i+1 )
continue;
//printf("[%03X]Entering:\"%s\" Level:%d leave:%04X\n", i, buffer + NameOff + swap24( fe[i].NameOffset ), level, swap32( fe[i].NextOffset ) );
Entry[level] = i;
LEntry[level++] = fe[i].NextOffset;
if( level > 15 ) // something is wrong!
break;
} else {
if( Offset >= fe[i].FileOffset )
{
u32 nOffset = (Offset - fe[i].FileOffset);
if( nOffset < fe[i].FileLength )
{
// dbgprintf("DIP:Offset:%08X FOffset:%08X Dif:%08X Flen:%08X nOffset:%08X\n", Offset, fe[i].FileOffset, Offset-fe[i].FileOffset, fe[i].FileLength, nOffset );
//Do not remove!
memset( Path, 0, 256 );
sprintf( Path, "%sroot/", GamePath );
for( j=0; j<level; ++j )
{
if( j )
Path[strlen(Path)] = '/';
memcpy( Path+strlen(Path), NameOff + fe[Entry[j]].NameOffset, strlen(NameOff + fe[Entry[j]].NameOffset ) );
}
if( level )
Path[strlen(Path)] = '/';
memcpy( Path+strlen(Path), NameOff + fe[i].NameOffset, strlen(NameOff + fe[i].NameOffset) );
if( FCEntry >= FILECACHE_MAX )
FCEntry = 0;
if( FCState[FCEntry] != 0xdeadbeef )
{
f_close( &(FC[FCEntry].File) );
FCState[FCEntry] = 0xdeadbeef;
}
Asciify( Path );
f_open( &(FC[FCEntry].File), Path, FA_READ );
FC[FCEntry].Size = fe[i].FileLength;
FC[FCEntry].Offset = fe[i].FileOffset;
FCState[FCEntry] = 0x23;
DVDCreateLinkMap(&(FC[FCEntry].File));
f_lseek( &(FC[FCEntry].File), nOffset );
f_read( &(FC[FCEntry].File), Buffer, Length, &read );
FCEntry++;
}
}
}
}
} else if ( Offset >= FSTableOffset ) {
Offset -= FSTableOffset;
sprintf( Path, "%ssys/fst.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[fst.bin] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
if( FSTable == NULL )
{
FSTable = (u8*)Buffer;
}
return;
}
} else if ( Offset >= dolOffset ) {
Offset -= dolOffset;
sprintf( Path, "%ssys/main.dol", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[main.dol] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
} else if ( Offset >= 0x2440 ) {
Offset -= 0x2440;
sprintf( Path, "%ssys/apploader.img", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[apploader.img] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
} else if ( Offset >= 0x440 ) {
Offset -= 0x440;
sprintf( Path, "%ssys/bi2.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[bi2.bin] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
} else {
sprintf( Path, "%ssys/boot.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[boot.bin] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
}
}