mirror of
https://github.com/dborth/vbagx.git
synced 2025-07-09 15:05:49 +02:00

* "Match Wii Game" controls option! Games that have a Wii equivalent can be played using the controls for that Wii game. For example all Zelda games can be played with Twilight Princess controls. See the Instructions section below for important details. * Rotation/Tilt sensor games all work * Solar sensors (Boktai 1/2/3) * Rumble (except for games that rely on Gameboy Player) * Keyboard * PAL support, finally! * New scaling options, choose how much stretching you want * Colourised games now partially work but still have distortion * "Corvette" no longer has a screwed up palette (but still crashes) * Triggers net reconnection on SMB failure * Source code refactored, and project file added * Instructions section added to this readme file
797 lines
21 KiB
C++
797 lines
21 KiB
C++
/****************************************************************************
|
|
* Visual Boy Advance GX
|
|
*
|
|
* Tantric September 2008
|
|
*
|
|
* dvd.cpp
|
|
*
|
|
* DVD I/O functions
|
|
***************************************************************************/
|
|
|
|
#include <gccore.h>
|
|
#include <ogcsys.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
|
|
#ifdef HW_RVL
|
|
extern "C" {
|
|
#include <di/di.h>
|
|
}
|
|
#endif
|
|
|
|
#include "menudraw.h"
|
|
#include "gcunzip.h"
|
|
#include "filesel.h"
|
|
#include "vba.h"
|
|
|
|
#define MAXDVDFILES 2000
|
|
|
|
static int diroffset = 0;
|
|
static u64 dvddir = 0; // offset of currently selected file or folder
|
|
static int dvddirlength = 0; // length of currently selected file or folder
|
|
static u64 dvdrootdir = 0; // offset of DVD root
|
|
static int dvdrootlength = 0; // length of DVD root
|
|
static bool isWii = false;
|
|
|
|
#ifdef HW_DOL
|
|
/** DVD I/O Address base **/
|
|
volatile unsigned long *dvd = (volatile unsigned long *) 0xCC006000;
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* dvd_read
|
|
*
|
|
* Main DVD function, everything else uses this!
|
|
* returns: 1 - ok ; 0 - error
|
|
***************************************************************************/
|
|
#define ALIGN_FORWARD(x,align) ((typeof(x))((((uint32_t)(x)) + (align) - 1) & (~(align-1))))
|
|
#define ALIGN_BACKWARD(x,align) ((typeof(x))(((uint32_t)(x)) & (~(align-1))))
|
|
|
|
static int
|
|
dvd_read (void *dst, unsigned int len, u64 offset)
|
|
{
|
|
if (len > 2048)
|
|
return 0; /*** We only allow 2k reads **/
|
|
|
|
// don't read past the end of the DVD (1.5 GB for GC DVD, 4.7 GB for DVD)
|
|
if((offset < 0x57057C00) || (isWii && (offset < 0x118244F00LL)))
|
|
{
|
|
u8 * buffer = (u8 *)memalign(32, 0x8000);
|
|
u32 off_size = 0;
|
|
|
|
DCInvalidateRange ((void *) buffer, len);
|
|
|
|
#ifdef HW_DOL
|
|
dvd[0] = 0x2E;
|
|
dvd[1] = 0;
|
|
dvd[2] = 0xA8000000;
|
|
dvd[3] = (u32)(offset >> 2);
|
|
dvd[4] = len;
|
|
dvd[5] = (u32) buffer;
|
|
dvd[6] = len;
|
|
dvd[7] = 3;
|
|
|
|
// Enable reading with DMA
|
|
while (dvd[7] & 1);
|
|
|
|
// Ensure it has completed
|
|
if (dvd[0] & 0x4)
|
|
return 0;
|
|
#else
|
|
off_size = offset - ALIGN_BACKWARD(offset,0x800);
|
|
if (DI_ReadDVD(
|
|
buffer,
|
|
(ALIGN_FORWARD(offset + len,0x800) - ALIGN_BACKWARD(offset,0x800)) >> 11,
|
|
(u32)(ALIGN_BACKWARD(offset, 0x800) >> 11)
|
|
))
|
|
return 0;
|
|
#endif
|
|
|
|
memcpy (dst, buffer+off_size, len);
|
|
free(buffer);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dvd_buffered_read
|
|
*
|
|
* the GC's dvd drive only supports offsets and length which are a multiple
|
|
* of 32 bytes additionally the max length of a read is 2048 bytes
|
|
* this function removes these limitations
|
|
* additionally the 7zip SDK does often read data in 1 byte parts from the
|
|
* DVD even when it could read 32 bytes. the dvdsf_buffer has been added to
|
|
* avoid having to read the same sector over and over again
|
|
***************************************************************************/
|
|
|
|
#define DVD_LENGTH_MULTIPLY 32
|
|
#define DVD_OFFSET_MULTIPLY 32
|
|
#define DVD_MAX_READ_LENGTH 2048
|
|
#define DVD_SECTOR_SIZE 2048
|
|
|
|
static unsigned char dvdsf_buffer[DVD_SECTOR_SIZE];
|
|
static u64 dvdsf_last_offset = 0;
|
|
static u64 dvdsf_last_length = 0;
|
|
|
|
static int dvd_buffered_read(void *dst, u32 len, u64 offset)
|
|
{
|
|
int ret = 1;
|
|
|
|
// only read data if the data inside dvdsf_buffer cannot be used
|
|
if(offset != dvdsf_last_offset || len > dvdsf_last_length)
|
|
{
|
|
memset(&dvdsf_buffer, '\0', DVD_SECTOR_SIZE);
|
|
ret = dvd_read(&dvdsf_buffer, len, offset);
|
|
dvdsf_last_offset = offset;
|
|
dvdsf_last_length = len;
|
|
}
|
|
|
|
memcpy(dst, &dvdsf_buffer, len);
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dvd_safe_read
|
|
*
|
|
* A 'safer' DVD read function
|
|
* This function relies on dvddir (file offset) being prepopulated!
|
|
* returns: 1 - ok ; 0 - error
|
|
***************************************************************************/
|
|
|
|
int dvd_safe_read(void *dst_v, u32 len, u64 fileoffset)
|
|
{
|
|
u64 offset = dvddir + fileoffset;
|
|
|
|
unsigned char buffer[DVD_SECTOR_SIZE]; // buffer for one dvd sector
|
|
|
|
// if read size and length are a multiply of DVD_(OFFSET,LENGTH)_MULTIPLY and length < DVD_MAX_READ_LENGTH
|
|
// we don't need to fix anything
|
|
if(len % DVD_LENGTH_MULTIPLY == 0 && offset % DVD_OFFSET_MULTIPLY == 0 && len <= DVD_MAX_READ_LENGTH)
|
|
{
|
|
int ret = dvd_buffered_read(buffer, len, offset);
|
|
memcpy(dst_v, &buffer, len);
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
// no errors yet -> ret = 1
|
|
// the return value of dvd_read will be AND'd with ret
|
|
// because dvd_read does return 0 on error and 1 on success and
|
|
// because 1 & 0 = 0 ret will also contain 0 if at least one error
|
|
// occured and 1 otherwise ;)
|
|
int ret = 1; // return value of dvd_read
|
|
|
|
// we might need to fix all 3 issues
|
|
unsigned char *dst = (unsigned char *)dst_v; // gcc will not allow to use var[num] on void* types
|
|
u64 bytesToRead; // the number of bytes we still need to read & copy to the output buffer
|
|
u64 currentOffset; // the current dvd offset
|
|
u64 bufferOffset; // the current buffer offset
|
|
u64 i, j, k; // temporary variables which might be used for different stuff
|
|
// unsigned char buffer[DVD_SECTOR_SIZE]; // buffer for one dvd sector
|
|
|
|
currentOffset = offset;
|
|
bytesToRead = len;
|
|
bufferOffset = 0;
|
|
|
|
// fix first issue (offset is not a multiply of 32)
|
|
if(offset % DVD_OFFSET_MULTIPLY)
|
|
{
|
|
// calculate offset of the prior 32 byte position
|
|
i = currentOffset - (currentOffset % DVD_OFFSET_MULTIPLY);
|
|
|
|
// calculate the offset from which the data of the dvd buffer will be copied
|
|
j = currentOffset % DVD_OFFSET_MULTIPLY;
|
|
|
|
// calculate the number of bytes needed to reach the next DVD_OFFSET_MULTIPLY byte mark
|
|
k = DVD_OFFSET_MULTIPLY - j;
|
|
|
|
// maybe we'll only need to copy a few bytes and we therefore don't even reach the next sector
|
|
if(k > len)
|
|
{
|
|
k = len;
|
|
}
|
|
|
|
// read 32 bytes from the last 32 byte position
|
|
ret &= dvd_buffered_read(buffer, DVD_OFFSET_MULTIPLY, i);
|
|
|
|
// copy the bytes to the output buffer and update currentOffset, bufferOffset and bytesToRead
|
|
memcpy(&dst[bufferOffset], &buffer[j], k);
|
|
currentOffset += k;
|
|
bufferOffset += k;
|
|
bytesToRead -= k;
|
|
}
|
|
|
|
// fix second issue (more than 2048 bytes are needed)
|
|
if(bytesToRead > DVD_MAX_READ_LENGTH)
|
|
{
|
|
// calculate the number of 2048 bytes sector needed to get all data
|
|
i = (bytesToRead - (bytesToRead % DVD_MAX_READ_LENGTH)) / DVD_MAX_READ_LENGTH;
|
|
|
|
// read data in 2048 byte sector
|
|
for(j = 0; j < i; j++)
|
|
{
|
|
ret &= dvd_buffered_read(buffer, DVD_MAX_READ_LENGTH, currentOffset); // read sector
|
|
memcpy(&dst[bufferOffset], buffer, DVD_MAX_READ_LENGTH); // copy to output buffer
|
|
|
|
// update currentOffset, bufferOffset and bytesToRead
|
|
currentOffset += DVD_MAX_READ_LENGTH;
|
|
bufferOffset += DVD_MAX_READ_LENGTH;
|
|
bytesToRead -= DVD_MAX_READ_LENGTH;
|
|
}
|
|
}
|
|
|
|
// fix third issue (length is not a multiply of 32)
|
|
if(bytesToRead)
|
|
{
|
|
ret &= dvd_buffered_read(buffer, DVD_MAX_READ_LENGTH, currentOffset); // read 32 byte from the dvd
|
|
memcpy(&dst[bufferOffset], buffer, bytesToRead); // copy bytes to output buffer
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/** Minimal ISO Directory Definition **/
|
|
#define RECLEN 0 /* Record length */
|
|
#define EXTENT 6 /* Extent */
|
|
#define FILE_LENGTH 14 /* File length (BIG ENDIAN) */
|
|
#define FILE_FLAGS 25 /* File flags */
|
|
#define FILENAME_LENGTH 32 /* Filename length */
|
|
#define FILENAME 33 /* ASCIIZ filename */
|
|
|
|
/** Minimal Primary Volume Descriptor **/
|
|
#define PVDROOT 0x9c
|
|
static int IsJoliet = 0;
|
|
|
|
/****************************************************************************
|
|
* Primary Volume Descriptor
|
|
*
|
|
* The PVD should reside between sector 16 and 31.
|
|
* This is for single session DVD only.
|
|
***************************************************************************/
|
|
static int
|
|
getpvd ()
|
|
{
|
|
int sector = 16;
|
|
u32 rootdir32;
|
|
unsigned char dvdbuffer[2048];
|
|
|
|
dvddir = dvddirlength = 0;
|
|
IsJoliet = -1;
|
|
|
|
/** Look for Joliet PVD first **/
|
|
while (sector < 32)
|
|
{
|
|
if (dvd_read (&dvdbuffer, 2048, (u64)(sector << 11)))
|
|
{
|
|
if (memcmp (&dvdbuffer, "\2CD001\1", 8) == 0)
|
|
{
|
|
memcpy(&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4);
|
|
dvddir = (u64)rootdir32;
|
|
dvddir <<= 11;
|
|
memcpy (&dvddirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4);
|
|
dvdrootdir = dvddir;
|
|
dvdrootlength = dvddirlength;
|
|
IsJoliet = 1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
return 0; /*** Can't read sector! ***/
|
|
sector++;
|
|
}
|
|
|
|
if (IsJoliet > 0) /*** Joliet PVD Found ? ***/
|
|
return 1;
|
|
|
|
sector = 16;
|
|
|
|
/*** Look for standard ISO9660 PVD ***/
|
|
while (sector < 32)
|
|
{
|
|
if (dvd_read (&dvdbuffer, 2048, sector << 11))
|
|
{
|
|
if (memcmp (&dvdbuffer, "\1CD001\1", 8) == 0)
|
|
{
|
|
memcpy (&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4);
|
|
dvddir = (u64)rootdir32;
|
|
dvddir <<= 11;
|
|
memcpy (&dvddirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4);
|
|
dvdrootdir = dvddir;
|
|
dvdrootlength = dvddirlength;
|
|
IsJoliet = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
return 0; /*** Can't read sector! ***/
|
|
sector++;
|
|
}
|
|
return (IsJoliet == 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* MountDVD()
|
|
*
|
|
* Tests if a ISO9660 DVD is inserted and available, and mounts it
|
|
***************************************************************************/
|
|
|
|
bool MountDVD(bool silent)
|
|
{
|
|
if (!getpvd())
|
|
{
|
|
ShowAction("Loading DVD...");
|
|
#ifdef HW_DOL
|
|
DVD_Mount(); // mount the DVD unit again
|
|
#elif HW_RVL
|
|
u32 val;
|
|
DI_GetCoverRegister(&val);
|
|
if(val & 0x1) // True if no disc inside, use (val & 0x2) for true if disc inside.
|
|
{
|
|
if(!silent)
|
|
WaitPrompt("No disc inserted!");
|
|
return false;
|
|
}
|
|
DI_Mount();
|
|
while(DI_GetStatus() & DVD_INIT);
|
|
#endif
|
|
|
|
if (!getpvd())
|
|
{
|
|
if(!silent)
|
|
WaitPrompt ("Invalid DVD.");
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* getentry
|
|
*
|
|
* Support function to return the next file entry, if any
|
|
* Declared static to avoid accidental external entry.
|
|
***************************************************************************/
|
|
|
|
static int
|
|
getentry (int entrycount, unsigned char dvdbuffer[])
|
|
{
|
|
char fname[512]; /* Huge, but experience has determined this */
|
|
char tmpname[512];
|
|
char *ptr;
|
|
char *filename;
|
|
char *filenamelength;
|
|
char *rr;
|
|
int j;
|
|
u32 offset32;
|
|
|
|
/* Basic checks */
|
|
if (entrycount >= MAXDVDFILES)
|
|
return 0;
|
|
|
|
if (diroffset >= 2048 || diroffset < 0)
|
|
return 0;
|
|
|
|
/** Decode this entry **/
|
|
if (dvdbuffer[diroffset]) /* Record length available */
|
|
{
|
|
/* Update offsets into sector buffer */
|
|
ptr = (char *) &dvdbuffer[0];
|
|
ptr += diroffset;
|
|
filename = ptr + FILENAME;
|
|
filenamelength = ptr + FILENAME_LENGTH;
|
|
|
|
/* Check for wrap round - illegal in ISO spec,
|
|
* but certain crap writers do it! */
|
|
if ((diroffset + dvdbuffer[diroffset]) > 2048 || (diroffset + dvdbuffer[diroffset]) < 0)
|
|
return 0;
|
|
|
|
if (*filenamelength)
|
|
{
|
|
memset (&fname, 0, 512);
|
|
|
|
if (!IsJoliet) /*** Do ISO 9660 first ***/
|
|
{
|
|
strncpy (fname, filename, 512);
|
|
}
|
|
else
|
|
{ /*** The more tortuous unicode joliet entries ***/
|
|
for (j = 0; j < (*filenamelength >> 1); j++)
|
|
{
|
|
fname[j] = filename[j * 2 + 1];
|
|
}
|
|
|
|
fname[j] = 0;
|
|
|
|
if (strlen (fname) >= MAXJOLIET)
|
|
fname[MAXJOLIET - 1] = 0;
|
|
|
|
if (strlen (fname) == 0)
|
|
fname[0] = filename[0];
|
|
}
|
|
|
|
if (strlen (fname) == 0) // root entry
|
|
{
|
|
fname[0] = 0; // we'll skip it by setting the filename to 0 length
|
|
}
|
|
else
|
|
{
|
|
if (fname[0] == 1)
|
|
{
|
|
if(dvddir == dvdrootdir) // at root already, don't show ..
|
|
fname[0] = 0;
|
|
else
|
|
strcpy (fname, "..");
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Move *filenamelength to t,
|
|
* Only to stop gcc warning for noobs :)
|
|
*/
|
|
int t = *filenamelength;
|
|
fname[t] = 0;
|
|
}
|
|
}
|
|
/** Rockridge Check **/
|
|
rr = strstr (fname, ";");
|
|
if (rr != NULL)
|
|
*rr = 0;
|
|
|
|
BROWSERENTRY * newBrowserList = (BROWSERENTRY *)realloc(browserList, (entrycount+1) * sizeof(BROWSERENTRY));
|
|
if(!newBrowserList) // failed to allocate required memory
|
|
{
|
|
ResetBrowser();
|
|
WaitPrompt("Out of memory: too many files!");
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
browserList = newBrowserList;
|
|
}
|
|
memset(&(browserList[entrycount]), 0, sizeof(BROWSERENTRY)); // clear the new entry
|
|
|
|
strncpy (browserList[entrycount].filename, fname, MAXJOLIET);
|
|
StripExt(tmpname, fname); // hide file extension
|
|
strncpy (browserList[entrycount].displayname, tmpname, MAXDISPLAY);
|
|
|
|
memcpy (&offset32, &dvdbuffer[diroffset + EXTENT], 4);
|
|
|
|
browserList[entrycount].offset = (u64)offset32;
|
|
memcpy (&(browserList[entrycount].length), &dvdbuffer[diroffset + FILE_LENGTH], 4);
|
|
memcpy (&(browserList[entrycount].isdir), &dvdbuffer[diroffset + FILE_FLAGS], 1);
|
|
|
|
browserList[entrycount].offset <<= 11;
|
|
browserList[entrycount].isdir = browserList[entrycount].isdir & 2;
|
|
|
|
/*** Prepare for next entry ***/
|
|
|
|
diroffset += dvdbuffer[diroffset];
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* ParseDVDdirectory
|
|
*
|
|
* This function will parse the directory tree.
|
|
* It relies on dvddir and dvddirlength being pre-populated by a call to
|
|
* getpvd, a previous parse or a menu selection.
|
|
*
|
|
* The return value is number of files collected, or 0 on failure.
|
|
***************************************************************************/
|
|
int
|
|
ParseDVDdirectory ()
|
|
{
|
|
int pdlength;
|
|
u64 pdoffset;
|
|
u64 rdoffset;
|
|
int len = 0;
|
|
int filecount = 0;
|
|
unsigned char dvdbuffer[2048];
|
|
|
|
// reset browser
|
|
ResetBrowser();
|
|
|
|
pdoffset = rdoffset = dvddir;
|
|
pdlength = dvddirlength;
|
|
filecount = 0;
|
|
|
|
/*** Get as many files as possible ***/
|
|
while (len < pdlength)
|
|
{
|
|
if (dvd_read (&dvdbuffer, 2048, pdoffset) == 0)
|
|
return 0;
|
|
|
|
diroffset = 0;
|
|
|
|
while (getentry (filecount, dvdbuffer))
|
|
{
|
|
if(strlen(browserList[filecount].filename) > 0 && filecount < MAXDVDFILES)
|
|
filecount++;
|
|
}
|
|
|
|
len += 2048;
|
|
pdoffset = rdoffset + len;
|
|
}
|
|
|
|
// Sort the file list
|
|
qsort(browserList, filecount, sizeof(BROWSERENTRY), FileSortCallback);
|
|
|
|
return filecount;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* SetDVDdirectory
|
|
* Set the current DVD file offset
|
|
***************************************************************************/
|
|
|
|
void SetDVDdirectory(u64 dir, int length)
|
|
{
|
|
dvddir = dir;
|
|
dvddirlength = length;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* DirectorySearch
|
|
*
|
|
* Searches for the directory name specified within the current directory
|
|
* Returns the index of the directory, or -1 if not found
|
|
***************************************************************************/
|
|
static int DirectorySearch(char dir[512])
|
|
{
|
|
for (int i = 0; i < browser.numEntries; i++ )
|
|
if (strcmp(browserList[i].filename, dir) == 0)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* SwitchDVDFolderR
|
|
*
|
|
* Recursively searches for any directory path 'dir' specified
|
|
* Also can be used to find and set the offset for a file
|
|
* Also loads the directory contents via ParseDVDdirectory()
|
|
* It relies on dvddir, dvddirlength, and filelist being pre-populated
|
|
***************************************************************************/
|
|
static bool SwitchDVDFolderR(char * dir, int maxDepth)
|
|
{
|
|
if(maxDepth > 8) // only search to a max depth of 8 levels
|
|
return false;
|
|
|
|
bool lastdir = false;
|
|
char * nextdir = NULL;
|
|
unsigned int t = strcspn(dir, "/");
|
|
|
|
if(t != strlen(dir))
|
|
nextdir = dir + t + 1; // next directory path to find
|
|
else
|
|
lastdir = true;
|
|
|
|
dir[t] = 0;
|
|
|
|
int dirindex = DirectorySearch(dir);
|
|
|
|
if(dirindex >= 0)
|
|
{
|
|
dvddir = browserList[dirindex].offset;
|
|
dvddirlength = browserList[dirindex].length;
|
|
browser.selIndex = dirindex;
|
|
|
|
if(browserList[dirindex].isdir) // only parse directories
|
|
browser.numEntries = ParseDVDdirectory();
|
|
|
|
if(lastdir)
|
|
return true;
|
|
else
|
|
return SwitchDVDFolderR(nextdir, maxDepth++);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SwitchDVDFolder(char origdir[])
|
|
{
|
|
// make a copy of origdir so we don't mess with original
|
|
char dir[200];
|
|
strcpy(dir, origdir);
|
|
|
|
char * dirptr = dir;
|
|
|
|
// strip off leading/trailing slashes on the directory path
|
|
// we don't want to screw up our recursion!
|
|
if(dir[0] == '/')
|
|
dirptr = dirptr + 1;
|
|
if(dir[strlen(dir)-1] == '/')
|
|
dir[strlen(dir)-1] = 0;
|
|
|
|
// start searching at root of DVD
|
|
dvddir = dvdrootdir;
|
|
dvddirlength = dvdrootlength;
|
|
ParseDVDdirectory();
|
|
|
|
return SwitchDVDFolderR(dirptr, 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* LoadDVDFileOffset
|
|
* This function will load a file from DVD
|
|
* It assumes dvddir and dvddirlength are prepopulated
|
|
***************************************************************************/
|
|
|
|
int
|
|
LoadDVDFileOffset (unsigned char *buffer, int length)
|
|
{
|
|
int offset;
|
|
int blocks;
|
|
int i;
|
|
int ret = 0;
|
|
u64 discoffset;
|
|
char readbuffer[2048];
|
|
|
|
// How many 2k blocks to read
|
|
blocks = dvddirlength / 2048;
|
|
offset = 0;
|
|
discoffset = dvddir;
|
|
ShowAction ("Loading...");
|
|
|
|
if(length > 0 && length <= 2048)
|
|
{
|
|
ret = dvd_read (buffer, length, discoffset);
|
|
if(ret <= 0) // read failure
|
|
return 0;
|
|
}
|
|
else // load whole file
|
|
{
|
|
ret = dvd_read (readbuffer, 2048, discoffset);
|
|
if(ret <= 0) // read failure
|
|
return 0;
|
|
|
|
if (IsZipFile (readbuffer))
|
|
{
|
|
return UnZipBuffer (buffer, METHOD_DVD); // unzip from dvd
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < blocks; i++)
|
|
{
|
|
ret = dvd_read (readbuffer, 2048, discoffset);
|
|
if(ret <= 0) // read failure
|
|
return 0;
|
|
memcpy (buffer + offset, readbuffer, 2048);
|
|
offset += 2048;
|
|
discoffset += 2048;
|
|
ShowProgress ("Loading...", offset, length);
|
|
}
|
|
|
|
/*** And final cleanup ***/
|
|
if (dvddirlength % 2048)
|
|
{
|
|
i = dvddirlength % 2048;
|
|
ret = dvd_read (readbuffer, 2048, discoffset);
|
|
if(ret <= 0) // read failure
|
|
return 0;
|
|
memcpy (buffer + offset, readbuffer, i);
|
|
}
|
|
}
|
|
}
|
|
return dvddirlength;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* LoadDVDFile
|
|
* This function will load a file from DVD, given a filepath
|
|
* It will attempt to find the offset of the file, and if successful it
|
|
* will populate dvddir and dvddirlength, and load the file
|
|
***************************************************************************/
|
|
|
|
int
|
|
LoadDVDFile(char * buffer, char *filepath, int datasize, bool silent)
|
|
{
|
|
if(SwitchDVDFolder(filepath))
|
|
{
|
|
return LoadDVDFileOffset ((unsigned char *)buffer, datasize);
|
|
}
|
|
else
|
|
{
|
|
if(!silent)
|
|
WaitPrompt("Error loading file!");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* uselessinquiry
|
|
*
|
|
* As the name suggests, this function is quite useless.
|
|
* It's only purpose is to stop any pending DVD interrupts while we use the
|
|
* memcard interface.
|
|
*
|
|
* libOGC tends to foul up if you don't, and sometimes does if you do!
|
|
***************************************************************************/
|
|
#ifdef HW_DOL
|
|
void uselessinquiry ()
|
|
{
|
|
dvd[0] = 0;
|
|
dvd[1] = 0;
|
|
dvd[2] = 0x12000000;
|
|
dvd[3] = 0;
|
|
dvd[4] = 0x20;
|
|
dvd[5] = 0x80000000;
|
|
dvd[6] = 0x20;
|
|
dvd[7] = 1;
|
|
|
|
while (dvd[7] & 1);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dvd_motor_off( )
|
|
* Turns off DVD drive motor so it doesn't make noise (Gamecube only)
|
|
***************************************************************************/
|
|
void dvd_motor_off ()
|
|
{
|
|
dvd[0] = 0x2e;
|
|
dvd[1] = 0;
|
|
dvd[2] = 0xe3000000;
|
|
dvd[3] = 0;
|
|
dvd[4] = 0;
|
|
dvd[5] = 0;
|
|
dvd[6] = 0;
|
|
dvd[7] = 1; // Do immediate
|
|
while (dvd[7] & 1);
|
|
|
|
/*** PSO Stops blackscreen at reload ***/
|
|
dvd[0] = 0x14;
|
|
dvd[1] = 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* dvd_driveid
|
|
*
|
|
* Gets and returns the dvd driveid
|
|
***************************************************************************/
|
|
|
|
int dvd_driveid()
|
|
{
|
|
static unsigned char *inquiry=(unsigned char *)0x80000004;
|
|
|
|
dvd[0] = 0x2e;
|
|
dvd[1] = 0;
|
|
dvd[2] = 0x12000000;
|
|
dvd[3] = 0;
|
|
dvd[4] = 0x20;
|
|
dvd[5] = 0x80000000;
|
|
dvd[6] = 0x20;
|
|
dvd[7] = 3;
|
|
|
|
while( dvd[7] & 1 )
|
|
;
|
|
DCFlushRange((void *)0x80000000, 32);
|
|
|
|
return (int)inquiry[2];
|
|
}
|
|
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* SetDVDDriveType()
|
|
*
|
|
* Sets the DVD drive ID for use to determine disc size (1.5 GB or 4.7 GB)
|
|
***************************************************************************/
|
|
void SetDVDDriveType()
|
|
{
|
|
#ifdef HW_RVL
|
|
isWii = true;
|
|
#else
|
|
int drvid = dvd_driveid ();
|
|
if ( drvid == 4 || drvid == 6 || drvid == 8 )
|
|
isWii = false;
|
|
else
|
|
isWii = true;
|
|
#endif
|
|
}
|