u32 U8Archive::FileDescriptor( const char *path ) const { int ret = EntryFromPath( path ); if( ret < 1 ) { return 0; } return ret; }
s32 U8Archive::EntryFromPath( const char *path, int d ) const { //gprintf( "EntryFromPath( \"%s\", %d )\n", path, d ); while( *path == '/' ) { path++; } if( !fst[ d ].filetype ) { gprintf("ERROR!! %s is not a directory\n", FstName( &fst[ d ] ) ); return -1; } u32 next = d + 1; FstEntry *entry = &fst[ next ]; while( next ) { //does this entry match. //strlen_slash is used because if looking for "dvd:/gameboy/" it would return a false positive if it hit "dvd:/gameboy advance/" first if( !strcasecmp_slash( path, FstName( entry ) ) && ( strlen( FstName( entry ) ) == (u32)strlen_slash( path ) ) ) { char *slash = strchr( path, '/' ); if( slash && *( slash + 1 ) ) { //we are looking for a file somewhere in this folder return EntryFromPath( slash + 1, next ); } //this is the actual entry we were looking for return next; } //find the next entry in this folder next = NextEntryInFolder( next, d ); entry = &fst[ next ]; } //no entry with the given path was found return -1; }
u8 *U8Archive::GetFile( const char *path, u32 *size ) const { if( !path || !fst || !name_table ) { return NULL; } s32 entryNo = EntryFromPath( path ); if( entryNo < 1 ) { //gprintf( "U8: entry wasn\'t found in the archive \"%s\"\n", path ); return NULL; } if( fst[ entryNo ].filetype ) { gprintf( "U8: \"%s\" is a folder\n", path ); return NULL; } if( size ) { *size = fst[ entryNo ].filelen; } return data + fst[ entryNo ].fileoffset; }
u8* U8NandArchive::GetFileAllocated( const char *path, u32 *size ) const { //gprintf( "U8NandArchive::GetFileAllocated( %s )\n" ); if( !path || !fst ) { return NULL; } // find file int f = EntryFromPath( path, 0 ); if( f < 1 || f >= (int)fst[ 0 ].filelen ) { gprintf( "U8: \"%s\" wasn't found in the archive.\n", path ); return NULL; } if( fst[ f ].filetype ) { gprintf( "U8: \"%s\" is a folder\n", path ); return NULL; } // create a buffer u8* ret = (u8*)memalign( 32, RU( fst[ f ].filelen, 32 ) ); if( !ret ) { gprintf( "U8: out of memory\n" ); return NULL; } // seek and read if( ISFS_Seek( fd, dataOffset + fst[ f ].fileoffset, SEEK_SET ) != (s32)( dataOffset + fst[ f ].fileoffset ) || ISFS_Read( fd, ret, fst[ f ].filelen ) != (s32)fst[ f ].filelen ) { free( ret ); gprintf( "U8: error reading data from nand\n" ); gprintf( "fd: %i fst[ fd ].filelen: %08x\n", fd, fst[ f ].filelen ); return NULL; } u32 len = fst[ f ].filelen; u8* ret2; // determine if it needs to be decompressed if( IsAshCompressed( ret, len ) ) { // ASH0 ret2 = DecompressAsh( ret, len ); if( !ret2 ) { free( ret ); gprintf( "out of memory\n" ); return NULL; } free( ret ); } else if( isLZ77compressed( ret ) ) { // LZ77 with no magic word if( decompressLZ77content( ret, len, &ret2, &len ) ) { free( ret ); return NULL; } free( ret ); } else if( *(u32*)( ret ) == 0x4C5A3737 )// LZ77 { // LZ77 with a magic word if( decompressLZ77content( ret + 4, len - 4, &ret2, &len ) ) { free( ret ); return NULL; } free( ret ); } else { // already got what we are after ret2 = ret; } if( size ) { *size = len; } // flush the cache so if there are any textures in this data, it will be ready for the GX DCFlushRange( ret2, len ); return ret2; }
void *DiHandler::ThreadMain( void *arg ) { enum State { St_Init, St_Reset, St_WaitForDisc, St_CheckDiscType, St_OpenPartition, St_WaitForDiscEject, // some error happened, dont do anything until the current disc is ejected St_Idle }; State state = St_Init; u32 coverState = 0; while( !threadExit ) { usleep( 1000 ); if( threadSleep ) LWP_SuspendThread( thread ); if( state == St_Init ) { if( WDVD_Init() ) { instance->ErrorHappened( E_Init, true ); threadExit = true; } state = St_Reset; continue; } else if( state == St_Reset ) { if( WDVD_Reset() ) { instance->ErrorHappened( E_Init, false ); continue; } state = St_WaitForDisc; } // check for disc u32 cover = 0; if( WDVD_GetCoverStatus( &cover ) ) { gprintf( "WDVD_GetCoverStatus() failed\n" ); WDVD_Close(); state = St_Init; continue; } // check if disc status is changed if( cover != coverState ) { //gprintf( "cover status: %08x %08x\n", cover, coverState ); if( cover & 2 )// disc is present and wasnt before { //gprintf( "disc inserted\n" ); instance->StartingToReadDisc(); WDVD_Reset(); state = St_CheckDiscType; } else if( coverState & 2 )// disc was present before isnt is gone now { instance->DiscEjected(); //gprintf( "disc ejected\n" ); state = St_WaitForDisc; } coverState = cover; } if( !( cover & 2 ) )// if theres no disc inserted, then loop { continue; } if( state == St_WaitForDiscEject ) { continue; } else if( state == St_CheckDiscType ) { s32 ret = WDVD_ReadDiskId( (void*)0x80000000 ); if( ret < 0 ) { gprintf("WDVD_ReadDiskId(): %d\n", ret ); instance->ErrorHappened( E_DVD_ReadError, false ); //state = St_WaitForDiscEject; WDVD_Close(); state = St_Init; //coverState = 0; continue; } // check disc type if( *(u32*)( 0x80000018 ) == 0x5d1c9ea3 ) { //gprintf( "disc is wii\n" ); state = St_OpenPartition; //instance->DiscInserted( T_Wii ); } else if( *(u32*)( 0x8000001c ) == 0xc2339f3d ) { //gprintf( "disc is gamecube\n" ); instance->DiscInserted( T_GC ); state = St_Idle; } else { //gprintf( "disc is unknown\n" ); instance->DiscInserted( T_Unknown ); state = St_WaitForDiscEject; //hexdump( (void*)0x80000000, 0x20 ); } } else if( state == St_OpenPartition ) { if( WDVD_OpenDataPartition() < 0 ) { instance->ErrorHappened( E_OpenPartition, false ); state = St_WaitForDiscEject; continue; } //gprintf( "partition is open\n" ); // search for the opening.bnr s32 ret; FST_INFO fst_info __attribute(( aligned( 32 ) )); //find FST inside partition ret = WDVD_Read( (u8*)&fst_info, sizeof( FST_INFO ), 0x420LL ); if( ret < 0 ) { gprintf("WDVD_Read( fst_info ): %d\n", ret ); instance->ErrorHappened( E_DVD_ReadError, false ); state = St_WaitForDiscEject; WDVD_ClosePartition(); continue; } fst_info.fst_offset <<= 2; fst_info.fst_size <<= 2; //gprintf( "%s %i\n", __FILE__, __LINE__ ); fst_buffer = (u8*)memalign( 32, RU( fst_info.fst_size, 0x40 ) ); if( !fst_buffer ) { instance->ErrorHappened( E_NoMem, true ); threadExit = true; WDVD_ClosePartition(); continue; } //gprintf( "%s %i\n", __FILE__, __LINE__ ); //gprintf( " %p %08x %08x\n", fst_buffer, fst_info.fst_size, fst_info.fst_offset ); //read fst into memory ret = WDVD_Read( fst_buffer, fst_info.fst_size, fst_info.fst_offset ); if( ret < 0 ) { gprintf("WDVD_Read( fst_buffer ): %d\n", ret ); instance->ErrorHappened( E_DVD_ReadError, false ); state = St_WaitForDiscEject; WDVD_ClosePartition(); continue; } //gprintf( "%s %i\n", __FILE__, __LINE__ ); //set the pointers fst = (FST_ENTRY *)fst_buffer; u32 name_table_offset = fst->filelen * 0xC; name_table = (char *)( fst_buffer + name_table_offset ); //gprintf( "%s %i\n", __FILE__, __LINE__ ); // find the opening.bnr int fd = EntryFromPath( "/opening.bnr", 0 ); if( fd < 2 ) { instance->ErrorHappened( E_NoOpeningBnr, false ); instance->DiscInserted( T_Wii ); FREE( fst ); name_table = NULL; state = St_Idle; WDVD_ClosePartition(); continue; } //gprintf( "%s %i\n", __FILE__, __LINE__ ); u32 len = fst[ fd ].filelen; u8 *buf = (u8*)memalign( 32, RU( len, 0x40 ) ); if( !buf ) { instance->ErrorHappened( E_NoMem, true ); threadExit = true; FREE( fst ); name_table = NULL; WDVD_ClosePartition(); continue; } //gprintf( "%s %i\n", __FILE__, __LINE__ ); ret = WDVD_Read( buf, len, (u64)( fst[ fd ].fileoffset ) << 2 ); if( ret < 0 ) { gprintf("WDVD_Read( opening.bnr ): %d\n", ret ); instance->ErrorHappened( E_DVD_ReadError, false ); state = St_WaitForDiscEject; FREE( fst ); name_table = NULL; free( buf ); WDVD_ClosePartition(); continue; } //gprintf( "%s %i\n", __FILE__, __LINE__ ); // done with these FREE( fst ); name_table = NULL; WDVD_ClosePartition(); //gprintf( "%s %i\n", __FILE__, __LINE__ ); bool rec = false; // got the opening.bnr. send it to whoever cares instance->OpeningBnrReady( buf, len, rec ); if( !rec ) { gprintf( "nobody got the banner. freeing it\n" ); free( buf ); } instance->DiscInserted( T_Wii ); //gprintf( "%s %i\n", __FILE__, __LINE__ ); state = St_Idle; } } return NULL; }