mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 09:32:58 +00:00
1853 lines
56 KiB
C
1853 lines
56 KiB
C
#include <tamtypes.h>
|
|
#include <loadcore.h>
|
|
#include <thsemap.h>
|
|
#include <intrman.h>
|
|
#include <thbase.h>
|
|
#include <loadcore.h>
|
|
#include <sifman.h>
|
|
#include <sifcmd.h>
|
|
#include <ioman.h>
|
|
#include <cdvdman.h>
|
|
#include <sysclib.h>
|
|
#include <stdio.h>
|
|
#include <sysmem.h>
|
|
|
|
#include "cdvd_iop.h"
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
enum PathMatch {
|
|
NOT_MATCH = 0,
|
|
MATCH,
|
|
SUBDIR
|
|
};
|
|
|
|
//#define DEBUG
|
|
|
|
// 16 sectors worth of toc entry
|
|
#define MAX_DIR_CACHE_SECTORS 32
|
|
|
|
|
|
//static u8 cdVolDescriptor[2048];
|
|
static sceCdRMode cdReadMode;
|
|
|
|
int lastsector;
|
|
int last_bk = 0;
|
|
|
|
|
|
struct rootDirTocHeader
|
|
{
|
|
u16 length;
|
|
u32 tocLBA;
|
|
u32 tocLBA_bigend;
|
|
u32 tocSize;
|
|
u32 tocSize_bigend;
|
|
u8 dateStamp[8];
|
|
u8 reserved[6];
|
|
u8 reserved2;
|
|
u8 reserved3;
|
|
} __attribute__((packed));
|
|
|
|
struct asciiDate
|
|
{
|
|
char year[4];
|
|
char month[2];
|
|
char day[2];
|
|
char hours[2];
|
|
char minutes[2];
|
|
char seconds[2];
|
|
char hundreths[2];
|
|
char terminator[1];
|
|
} __attribute__((packed));
|
|
|
|
struct cdVolDesc
|
|
{
|
|
u8 filesystemType; // 0x01 = ISO9660, 0x02 = Joliet, 0xFF = NULL
|
|
u8 volID[5]; // "CD001"
|
|
u8 reserved2;
|
|
u8 reserved3;
|
|
u8 sysIdName[32];
|
|
u8 volName[32]; // The ISO9660 Volume Name
|
|
u8 reserved5[8];
|
|
u32 volSize; // Volume Size
|
|
u32 volSizeBig; // Volume Size Big-Endian
|
|
u8 reserved6[32];
|
|
u32 unknown1;
|
|
u32 unknown1_bigend;
|
|
u16 volDescSize;
|
|
u16 volDescSize_bigend;
|
|
u32 unknown3;
|
|
u32 unknown3_bigend;
|
|
u32 priDirTableLBA; // LBA of Primary Dir Table
|
|
u32 reserved7;
|
|
u32 secDirTableLBA; // LBA of Secondary Dir Table
|
|
u32 reserved8;
|
|
struct rootDirTocHeader rootToc;
|
|
u8 volSetName[128];
|
|
u8 publisherName[128];
|
|
u8 preparerName[128];
|
|
u8 applicationName[128];
|
|
u8 copyrightFileName[37];
|
|
u8 abstractFileName[37];
|
|
u8 bibliographyFileName[37];
|
|
struct asciiDate creationDate;
|
|
struct asciiDate modificationDate;
|
|
struct asciiDate effectiveDate;
|
|
struct asciiDate expirationDate;
|
|
u8 reserved10;
|
|
u8 reserved11[1166];
|
|
} __attribute__((packed));
|
|
|
|
struct dirTableEntry
|
|
{
|
|
u8 dirNameLength;
|
|
u8 reserved;
|
|
u32 dirTOCLBA;
|
|
u16 dirDepth;
|
|
u8 dirName[32];
|
|
} __attribute__((packed));
|
|
|
|
struct dirTocEntry
|
|
{
|
|
short length;
|
|
unsigned int fileLBA;
|
|
unsigned int fileLBA_bigend;
|
|
unsigned int fileSize;
|
|
unsigned int fileSize_bigend;
|
|
unsigned char dateStamp[6];
|
|
unsigned char reserved1;
|
|
unsigned char fileProperties;
|
|
unsigned char reserved2[6];
|
|
unsigned char filenameLength;
|
|
unsigned char filename[128];
|
|
} __attribute__((packed)); // This is the internal format on the CD
|
|
// a file with a single character filename will have a 34byte toc entry
|
|
// (max 60 entries per sector)6
|
|
|
|
// TocEntry structure contains only the important stuff needed for export
|
|
//
|
|
|
|
struct fdtable
|
|
{
|
|
iop_file_t *fd;
|
|
int fileSize;
|
|
int LBA;
|
|
int filePos;
|
|
};
|
|
|
|
|
|
struct dir_cache_info
|
|
{
|
|
char pathname[1024]; // The pathname of the cached directory
|
|
unsigned int valid; // TRUE if cache data is valid, FALSE if not
|
|
|
|
unsigned int path_depth; // The path depth of the cached directory (0 = root)
|
|
|
|
unsigned int sector_start; // The start sector (LBA) of the cached directory
|
|
unsigned int sector_num; // The total size of the directory (in sectors)
|
|
unsigned int cache_offset; // The offset from sector_start of the cached area
|
|
unsigned int cache_size; // The size of the cached directory area (in sectors)
|
|
|
|
char *cache; // The actual cached data
|
|
};
|
|
|
|
|
|
static struct dir_cache_info CachedDirInfo;
|
|
|
|
enum Cache_getMode {
|
|
CACHE_START = 0,
|
|
CACHE_NEXT = 1
|
|
};
|
|
|
|
static struct cdVolDesc CDVolDesc;
|
|
|
|
static unsigned int *buffer; // RPC send/receive buffer
|
|
struct t_SifRpcDataQueue qd;
|
|
struct t_SifRpcServerData sd0;
|
|
|
|
|
|
static struct fdtable fd_table[16];
|
|
static int fd_used[16];
|
|
static int files_open;
|
|
|
|
static iop_device_t file_driver;
|
|
|
|
/* Filing-system exported functions */
|
|
int CDVD_init(iop_device_t *driver);
|
|
int CDVD_open(iop_file_t *f, const char *name, int mode);
|
|
int CDVD_lseek(iop_file_t *f, int offset, int whence);
|
|
int CDVD_read(iop_file_t *f, void *buffer, int size);
|
|
int CDVD_write(iop_file_t *f, void *buffer, int size);
|
|
int CDVD_close(iop_file_t *f);
|
|
|
|
/* RPC exported functions */
|
|
int CDVD_findfile(const char *fname, struct TocEntry *tocEntry);
|
|
int CDVD_stop(void);
|
|
int CDVD_trayreq(int mode);
|
|
int CDVD_diskready(void);
|
|
int CDVD_GetDir_RPC(const char *pathname, const char *extensions, enum CDVD_getMode getMode, struct TocEntry tocEntry[], unsigned int req_entries);
|
|
|
|
int CDVD_getdir_IOP(const char *pathname, const char *extensions, enum CDVD_getMode getMode, struct TocEntry tocEntry[], unsigned int req_entries);
|
|
|
|
|
|
// Functions called by the RPC server
|
|
void *CDVDRpc_Stop();
|
|
void *CDVDRpc_FlushCache();
|
|
void *CDVDRpc_TrayReq(unsigned int *sbuff);
|
|
void *CDVDRpc_DiskReady(unsigned int *sbuff);
|
|
void *CDVDRpc_FindFile(unsigned int *sbuff);
|
|
void *CDVDRpc_Getdir(unsigned int *sbuff);
|
|
void *CDVDRpc_GetSize(unsigned int *sbuff);
|
|
|
|
|
|
/* Internal use functions */
|
|
int isValidDisc(void);
|
|
int strcasecmp(const char *s1, const char *s2);
|
|
int strncasecmp(const char *s1, const char *s2, int limit);
|
|
int CDVD_GetVolumeDescriptor(void);
|
|
void _splitpath(const char *constpath, char *dir, char *fname);
|
|
void TocEntryCopy(struct TocEntry *tocEntry, struct dirTocEntry *internalTocEntry);
|
|
int TocEntryCompare(char *filename, const char *extensions);
|
|
|
|
enum PathMatch ComparePath(const char *path);
|
|
|
|
int CDVD_Cache_Dir(const char *pathname, enum Cache_getMode getMode);
|
|
int FindPath(char *pathname);
|
|
|
|
|
|
void *CDVD_rpc_server(int fno, void *data, int size);
|
|
void CDVD_Thread(void *param);
|
|
|
|
|
|
|
|
/********************
|
|
* Optimised CD Read *
|
|
********************/
|
|
|
|
int ReadSect(u32 lsn, u32 sectors, void *buf, sceCdRMode *mode)
|
|
{
|
|
int retry;
|
|
int result = 0;
|
|
cdReadMode.trycount = 32;
|
|
|
|
for (retry = 0; retry < 32; retry++) // 32 retries
|
|
{
|
|
if (retry <= 8)
|
|
cdReadMode.spindlctrl = 1; // Try fast reads for first 8 tries
|
|
else
|
|
cdReadMode.spindlctrl = 0; // Then try slow reads
|
|
|
|
if (!isValidDisc())
|
|
return FALSE;
|
|
|
|
sceCdDiskReady(0);
|
|
|
|
if (sceCdRead(lsn, sectors, buf, mode) != TRUE) {
|
|
// Failed to read
|
|
if (retry == 31) {
|
|
// Still failed after last retry
|
|
memset(buf, 0, (sectors << 11));
|
|
// printf("Couldn't Read from file for some reason\n");
|
|
return FALSE; // error
|
|
}
|
|
} else {
|
|
// Read okay
|
|
sceCdSync(0);
|
|
break;
|
|
}
|
|
|
|
result = sceCdGetError();
|
|
if (result == 0)
|
|
break;
|
|
}
|
|
|
|
cdReadMode.trycount = 32;
|
|
cdReadMode.spindlctrl = 1;
|
|
|
|
if (result == 0)
|
|
return TRUE;
|
|
|
|
memset(buf, 0, (sectors << 11));
|
|
|
|
return FALSE; // error
|
|
}
|
|
|
|
/***********************************************
|
|
* Determines if there is a valid disc inserted *
|
|
***********************************************/
|
|
int isValidDisc(void)
|
|
{
|
|
int result;
|
|
|
|
switch (sceCdGetDiskType()) {
|
|
case SCECdPSCD:
|
|
case SCECdPSCDDA:
|
|
case SCECdPS2CD:
|
|
case SCECdPS2CDDA:
|
|
case SCECdPS2DVD:
|
|
result = 1;
|
|
break;
|
|
default:
|
|
result = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*************************************************************
|
|
* The functions below are the normal file-system operations, *
|
|
* used to provide a standard filesystem interface. There is *
|
|
* no need to export these functions for calling via RPC *
|
|
*************************************************************/
|
|
int dummy()
|
|
{
|
|
#ifdef DEBUG
|
|
printf("CDVD: dummy function called\n");
|
|
#endif
|
|
|
|
return -5;
|
|
}
|
|
|
|
int CDVD_init(iop_device_t *driver)
|
|
{
|
|
printf("CDVD: CDVD Filesystem v1.15\n");
|
|
printf("by A.Lee (aka Hiryu) & Nicholas Van Veen (aka Sjeep)\n");
|
|
printf("CDVD: Initializing '%s' file driver.\n", driver->name);
|
|
|
|
sceCdInit(SCECdINoD);
|
|
|
|
memset(fd_table, 0, sizeof(fd_table));
|
|
memset(fd_used, 0, 16 * 4);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CDVD_deinit(iop_device_t *driver)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int CDVD_open(iop_file_t *f, const char *name, int mode)
|
|
{
|
|
int j;
|
|
static struct TocEntry tocEntry;
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD: fd_open called.\n");
|
|
printf(" kernel_fd.. %p\n", f);
|
|
printf(" name....... %s %x\n", name, (int)name);
|
|
printf(" mode....... %d\n\n", mode);
|
|
#endif
|
|
|
|
// check if the file exists
|
|
if (CDVD_findfile(name, &tocEntry) != TRUE) {
|
|
return -1;
|
|
}
|
|
|
|
if (mode != O_RDONLY)
|
|
return -2;
|
|
|
|
// set up a new file descriptor
|
|
for (j = 0; j < 16; j++) {
|
|
if (fd_used[j] == 0)
|
|
break;
|
|
}
|
|
|
|
if (j >= 16)
|
|
return -3;
|
|
|
|
|
|
fd_used[j] = 1;
|
|
files_open++;
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD: internal fd %d\n", j);
|
|
#endif
|
|
|
|
fd_table[j].fd = f;
|
|
fd_table[j].fileSize = tocEntry.fileSize;
|
|
fd_table[j].LBA = tocEntry.fileLBA;
|
|
fd_table[j].filePos = 0;
|
|
|
|
#ifdef DEBUG
|
|
printf("tocEntry.fileSize = %d\n", tocEntry.fileSize);
|
|
|
|
printf("Opened file: %s\n", name);
|
|
#endif
|
|
|
|
return j;
|
|
}
|
|
|
|
|
|
|
|
int CDVD_lseek(iop_file_t *f, int offset, int whence)
|
|
{
|
|
int i;
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD: fd_seek called.\n");
|
|
printf(" kernel_fd... %p\n", f);
|
|
printf(" offset...... %d\n", offset);
|
|
printf(" whence...... %d\n\n", whence);
|
|
#endif
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
if (fd_table[i].fd == f)
|
|
break;
|
|
}
|
|
|
|
if (i >= 16) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_lseek: ERROR: File does not appear to be open!\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
fd_table[i].filePos = offset;
|
|
break;
|
|
|
|
case SEEK_CUR:
|
|
fd_table[i].filePos += offset;
|
|
break;
|
|
|
|
case SEEK_END:
|
|
fd_table[i].filePos = fd_table[i].fileSize + offset;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
if (fd_table[i].filePos < 0)
|
|
fd_table[i].filePos = 0;
|
|
|
|
if (fd_table[i].filePos > fd_table[i].fileSize)
|
|
fd_table[i].filePos = fd_table[i].fileSize;
|
|
|
|
return fd_table[i].filePos;
|
|
}
|
|
|
|
|
|
int CDVD_read(iop_file_t *f, void *buffer, int size)
|
|
{
|
|
int i;
|
|
|
|
int start_sector;
|
|
int off_sector;
|
|
int num_sectors;
|
|
|
|
int read = 0;
|
|
// int sector;
|
|
|
|
// int size_left;
|
|
// int copy_size;
|
|
|
|
static char local_buffer[9 * 2048];
|
|
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD: read called\n");
|
|
printf(" kernel_fd... %p\n", f);
|
|
printf(" buffer...... 0x%X\n", (int)buffer);
|
|
printf(" size........ %d\n\n", size);
|
|
#endif
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
if (fd_table[i].fd == f)
|
|
break;
|
|
}
|
|
|
|
if (i >= 16) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_read: ERROR: File does not appear to be open!\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
// A few sanity checks
|
|
if (fd_table[i].filePos > fd_table[i].fileSize) {
|
|
// We cant start reading from past the beginning of the file
|
|
return 0; // File exists but we couldnt read anything from it
|
|
}
|
|
|
|
if ((fd_table[i].filePos + size) > fd_table[i].fileSize)
|
|
size = fd_table[i].fileSize - fd_table[i].filePos;
|
|
|
|
if (size <= 0)
|
|
return 0;
|
|
|
|
if (size > 16384)
|
|
size = 16384;
|
|
|
|
// Now work out where we want to start reading from
|
|
start_sector = fd_table[i].LBA + (fd_table[i].filePos >> 11);
|
|
off_sector = (fd_table[i].filePos & 0x7FF);
|
|
|
|
num_sectors = (off_sector + size);
|
|
num_sectors = (num_sectors >> 11) + ((num_sectors & 2047) != 0);
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD_read: read sectors %d to %d\n", start_sector, start_sector + num_sectors);
|
|
#endif
|
|
|
|
// Skip a Sector for equal (use the last sector in buffer)
|
|
if (start_sector == lastsector) {
|
|
read = 1;
|
|
if (last_bk > 0)
|
|
memcpy(local_buffer, local_buffer + 2048 * (last_bk), 2048);
|
|
last_bk = 0;
|
|
}
|
|
|
|
lastsector = start_sector + num_sectors - 1;
|
|
// Read the data (we only ever get 16KB max request at once)
|
|
|
|
if (read == 0 || (read == 1 && num_sectors > 1)) {
|
|
if (ReadSect(start_sector + read, num_sectors - read, local_buffer + ((read) << 11), &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from file for some reason\n");
|
|
#endif
|
|
}
|
|
|
|
last_bk = num_sectors - 1;
|
|
}
|
|
|
|
memcpy(buffer, local_buffer + off_sector, size);
|
|
|
|
fd_table[i].filePos += size;
|
|
|
|
return (size);
|
|
}
|
|
|
|
|
|
int CDVD_write(iop_file_t *f, void *buffer, int size)
|
|
{
|
|
if (size == 0)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
int CDVD_close(iop_file_t *f)
|
|
{
|
|
int i;
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD: fd_close called.\n");
|
|
printf(" kernel fd.. %p\n\n", f);
|
|
#endif
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
if (fd_table[i].fd == f)
|
|
break;
|
|
}
|
|
|
|
if (i >= 16) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_close: ERROR: File does not appear to be open!\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD: internal fd %d\n", i);
|
|
#endif
|
|
|
|
fd_used[i] = 0;
|
|
files_open--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static iop_device_ops_t filedriver_ops = {
|
|
&CDVD_init,
|
|
&CDVD_deinit,
|
|
(void *)&dummy,
|
|
&CDVD_open,
|
|
&CDVD_close,
|
|
&CDVD_read,
|
|
&CDVD_write,
|
|
&CDVD_lseek,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy,
|
|
(void *)&dummy};
|
|
|
|
int _start(int argc, char **argv)
|
|
{
|
|
int i;
|
|
struct _iop_thread param;
|
|
int th;
|
|
|
|
// Initialise the directory cache
|
|
strcpy(CachedDirInfo.pathname, ""); // The pathname of the cached directory
|
|
CachedDirInfo.valid = FALSE; // Cache is not valid
|
|
CachedDirInfo.path_depth = 0; // 0 = root)
|
|
CachedDirInfo.sector_start = 0; // The start sector (LBA) of the cached directory
|
|
CachedDirInfo.sector_num = 0; // The total size of the directory (in sectors)
|
|
CachedDirInfo.cache_offset = 0; // The offset from sector_start of the cached area
|
|
CachedDirInfo.cache_size = 0; // The size of the cached directory area (in sectors)
|
|
|
|
if (CachedDirInfo.cache == NULL)
|
|
CachedDirInfo.cache = (char *)AllocSysMemory(0, MAX_DIR_CACHE_SECTORS * 2048, NULL);
|
|
|
|
|
|
// setup the cdReadMode structure
|
|
cdReadMode.trycount = 0;
|
|
cdReadMode.spindlctrl = SCECdSpinStm;
|
|
cdReadMode.datapattern = SCECdSecS2048;
|
|
|
|
// setup the file_driver structure
|
|
file_driver.name = "cdfs";
|
|
file_driver.type = IOP_DT_FS;
|
|
file_driver.version = 1;
|
|
file_driver.desc = "CDVD Filedriver";
|
|
file_driver.ops = &filedriver_ops;
|
|
|
|
DelDrv("cdfs");
|
|
AddDrv(&file_driver);
|
|
|
|
param.attr = TH_C;
|
|
param.thread = (void *)CDVD_Thread;
|
|
param.priority = 40;
|
|
param.stacksize = 0x8000;
|
|
param.option = 0;
|
|
|
|
th = CreateThread(¶m);
|
|
|
|
if (th > 0) {
|
|
StartThread(th, NULL);
|
|
return MODULE_RESIDENT_END;
|
|
} else
|
|
return MODULE_NO_RESIDENT_END;
|
|
}
|
|
|
|
/**************************************************************
|
|
* The functions below are not exported for normal file-system *
|
|
* operations, but are used by the file-system operations, and *
|
|
* may also be exported for use via RPC *
|
|
**************************************************************/
|
|
|
|
|
|
int CDVD_GetVolumeDescriptor(void)
|
|
{
|
|
// Read until we find the last valid Volume Descriptor
|
|
int volDescSector;
|
|
|
|
static struct cdVolDesc localVolDesc;
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD_GetVolumeDescriptor called\n");
|
|
#endif
|
|
|
|
for (volDescSector = 16; volDescSector < 20; volDescSector++) {
|
|
ReadSect(volDescSector, 1, &localVolDesc, &cdReadMode);
|
|
|
|
// If this is still a volume Descriptor
|
|
if (strncmp(localVolDesc.volID, "CD001", 5) == 0) {
|
|
if ((localVolDesc.filesystemType == 1) ||
|
|
(localVolDesc.filesystemType == 2)) {
|
|
memcpy(&CDVolDesc, &localVolDesc, sizeof(struct cdVolDesc));
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
switch (CDVolDesc.filesystemType) {
|
|
case 1:
|
|
printf("CD FileSystem is ISO9660\n");
|
|
break;
|
|
|
|
case 2:
|
|
printf("CD FileSystem is Joliet\n");
|
|
break;
|
|
|
|
default:
|
|
printf("CD FileSystem is unknown type\n");
|
|
break;
|
|
}
|
|
#endif
|
|
// sceCdStop();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
int CDVD_findfile(const char *fname, struct TocEntry *tocEntry)
|
|
{
|
|
static char filename[128 + 1];
|
|
static char pathname[1024 + 1];
|
|
|
|
struct dirTocEntry *tocEntryPointer;
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD_findfile called\n");
|
|
#endif
|
|
|
|
_splitpath(fname, pathname, filename);
|
|
|
|
#ifdef DEBUG
|
|
printf("Trying to find file: %s in directory: %s\n", filename, pathname);
|
|
#endif
|
|
|
|
// if ((CachedDirInfo.valid==TRUE)
|
|
// && (strcasecmp(pathname, CachedDirInfo.pathname)==0))
|
|
|
|
if ((CachedDirInfo.valid == TRUE) && (ComparePath(pathname) == MATCH)) {
|
|
// the directory is already cached, so check through the currently
|
|
// cached chunk of the directory first
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
|
|
for (; tocEntryPointer < (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048)); tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
|
|
if (tocEntryPointer->length == 0) {
|
|
#ifdef DEBUG
|
|
printf("Got a null pointer entry, so either reached end of dir, or end of sector\n");
|
|
#endif
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)(CachedDirInfo.cache + (((((char *)tocEntryPointer - CachedDirInfo.cache) / 2048) + 1) * 2048));
|
|
}
|
|
|
|
if (tocEntryPointer >= (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048))) {
|
|
// reached the end of the cache block
|
|
break;
|
|
}
|
|
|
|
if ((tocEntryPointer->fileProperties & 0x02) == 0) {
|
|
// It's a file
|
|
TocEntryCopy(tocEntry, tocEntryPointer);
|
|
|
|
if (strcasecmp(tocEntry->filename, filename) == 0) {
|
|
// and it matches !!
|
|
return TRUE;
|
|
}
|
|
}
|
|
} // end of for loop
|
|
|
|
|
|
|
|
// If that was the only dir block, and we havent found it, then fail
|
|
if (CachedDirInfo.cache_size == CachedDirInfo.sector_num)
|
|
return FALSE;
|
|
|
|
// Otherwise there is more dir to check
|
|
if (CachedDirInfo.cache_offset == 0) {
|
|
// If that was the first block then continue with the next block
|
|
if (CDVD_Cache_Dir(pathname, CACHE_NEXT) != TRUE)
|
|
return FALSE;
|
|
} else {
|
|
// otherwise (if that wasnt the first block) then start checking from the start
|
|
if (CDVD_Cache_Dir(pathname, CACHE_START) != TRUE)
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
#ifdef DEBUG
|
|
printf("Trying to cache directory\n");
|
|
#endif
|
|
// The wanted directory wasnt already cached, so cache it now
|
|
if (CDVD_Cache_Dir(pathname, CACHE_START) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Failed to cache directory\n");
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// If we've got here, then we have a block of the directory cached, and want to check
|
|
// from this point, to the end of the dir
|
|
#ifdef DEBUG
|
|
printf("cache_size = %d\n", CachedDirInfo.cache_size);
|
|
#endif
|
|
|
|
while (CachedDirInfo.cache_size > 0) {
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
|
|
if (CachedDirInfo.cache_offset == 0)
|
|
tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
|
|
|
|
for (; tocEntryPointer < (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048)); tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
|
|
if (tocEntryPointer->length == 0) {
|
|
#ifdef DEBUG
|
|
printf("Got a null pointer entry, so either reached end of dir, or end of sector\n");
|
|
printf("Offset into cache = %d bytes\n", (char *)tocEntryPointer - CachedDirInfo.cache);
|
|
#endif
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)(CachedDirInfo.cache + (((((char *)tocEntryPointer - CachedDirInfo.cache) / 2048) + 1) * 2048));
|
|
}
|
|
|
|
if (tocEntryPointer >= (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048))) {
|
|
// reached the end of the cache block
|
|
break;
|
|
}
|
|
|
|
TocEntryCopy(tocEntry, tocEntryPointer);
|
|
|
|
if (strcasecmp(tocEntry->filename, filename) == 0) {
|
|
#ifdef DEBUG
|
|
printf("Found a matching file\n");
|
|
#endif
|
|
// and it matches !!
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("Non-matching file - looking for %s , found %s\n", filename, tocEntry->filename);
|
|
#endif
|
|
} // end of for loop
|
|
|
|
#ifdef DEBUG
|
|
printf("Reached end of cache block\n");
|
|
#endif
|
|
// cache the next block
|
|
CDVD_Cache_Dir(pathname, CACHE_NEXT);
|
|
}
|
|
|
|
// we've run out of dir blocks to cache, and still not found it, so fail
|
|
|
|
#ifdef DEBUG
|
|
printf("CDVD_findfile: could not find file\n");
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// Find, and cache, the requested directory, for use by GetDir or (and thus open)
|
|
// provide an optional offset variable, for use when caching dirs of greater than 500 files
|
|
|
|
// returns TRUE if all TOC entries have been retrieved, or
|
|
// returns FALSE if there are more TOC entries to be retrieved
|
|
int CDVD_Cache_Dir(const char *pathname, enum Cache_getMode getMode)
|
|
{
|
|
|
|
// macke sure that the requested pathname is not directly modified
|
|
static char dirname[1024];
|
|
|
|
int path_len;
|
|
|
|
#ifdef DEBUG
|
|
printf("Attempting to find, and cache, directory: %s\n", pathname);
|
|
#endif
|
|
|
|
// only take any notice of the existing cache, if it's valid
|
|
if (CachedDirInfo.valid == TRUE) {
|
|
// Check if the requested path is already cached
|
|
// if (strcasecmp(pathname,CachedDirInfo.pathname)==0)
|
|
if (ComparePath(pathname) == MATCH) {
|
|
#ifdef DEBUG
|
|
printf("CacheDir: The requested path is already cached\n");
|
|
#endif
|
|
|
|
// If so, is the request ot cache the start of the directory, or to resume the next block ?
|
|
if (getMode == CACHE_START) {
|
|
#ifdef DEBUG
|
|
printf(" and requested cache from start of dir\n");
|
|
#endif
|
|
|
|
if (CachedDirInfo.cache_offset == 0) {
|
|
// requested cache of start of the directory, and thats what's already cached
|
|
// so sit back and do nothing
|
|
#ifdef DEBUG
|
|
printf(" and start of dir is already cached so nothing to do :o)\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = TRUE;
|
|
return TRUE;
|
|
} else {
|
|
// Requested cache of start of the directory, but thats not what's cached
|
|
// so re-cache the start of the directory
|
|
|
|
#ifdef DEBUG
|
|
printf(" but dir isn't cached from start, so re-cache existing dir from start\n");
|
|
#endif
|
|
|
|
// reset cache data to start of existing directory
|
|
CachedDirInfo.cache_offset = 0;
|
|
CachedDirInfo.cache_size = CachedDirInfo.sector_num;
|
|
|
|
if (CachedDirInfo.cache_size > MAX_DIR_CACHE_SECTORS)
|
|
CachedDirInfo.cache_size = MAX_DIR_CACHE_SECTORS;
|
|
|
|
// Now fill the cache with the specified sectors
|
|
if (ReadSect(CachedDirInfo.sector_start + CachedDirInfo.cache_offset, CachedDirInfo.cache_size, CachedDirInfo.cache, &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from CD !\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = FALSE; // should we completely invalidate just because we couldnt read first time?
|
|
return FALSE;
|
|
}
|
|
|
|
CachedDirInfo.valid = TRUE;
|
|
return TRUE;
|
|
}
|
|
} else // getMode == CACHE_NEXT
|
|
{
|
|
// So get the next block of the existing directory
|
|
|
|
CachedDirInfo.cache_offset += CachedDirInfo.cache_size;
|
|
|
|
CachedDirInfo.cache_size = CachedDirInfo.sector_num - CachedDirInfo.cache_offset;
|
|
|
|
if (CachedDirInfo.cache_size > MAX_DIR_CACHE_SECTORS)
|
|
CachedDirInfo.cache_size = MAX_DIR_CACHE_SECTORS;
|
|
|
|
// Now fill the cache with the specified sectors
|
|
if (ReadSect(CachedDirInfo.sector_start + CachedDirInfo.cache_offset, CachedDirInfo.cache_size, CachedDirInfo.cache, &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from CD !\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = FALSE; // should we completely invalidate just because we couldnt read first time?
|
|
return FALSE;
|
|
}
|
|
|
|
CachedDirInfo.valid = TRUE;
|
|
return TRUE;
|
|
}
|
|
} else // requested directory is not the cached directory (but cache is still valid)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("Cache is valid, but cached directory, is not the requested one\n"
|
|
"so check if the requested directory is a sub-dir of the cached one\n");
|
|
|
|
printf("Requested Path = %s , Cached Path = %s\n", pathname, CachedDirInfo.pathname);
|
|
#endif
|
|
|
|
|
|
// Is the requested pathname a sub-directory of the current-directory ?
|
|
|
|
// if the requested pathname is longer than the pathname of the cached dir
|
|
// and the pathname of the cached dir matches the beginning of the requested pathname
|
|
// and the next character in the requested pathname is a dir seperator
|
|
// printf("Length of Cached pathname = %d, length of req'd pathname = %d\n",path_len, strlen(pathname));
|
|
// printf("Result of strncasecmp = %d\n",strncasecmp(pathname, CachedDirInfo.pathname, path_len));
|
|
// printf("next character after length of cached name = %c\n",pathname[path_len]);
|
|
|
|
// if ((strlen(pathname) > path_len)
|
|
// && (strncasecmp(pathname, CachedDirInfo.pathname, path_len)==0)
|
|
// && ((pathname[path_len]=='/') || (pathname[path_len]=='\\')))
|
|
|
|
if (ComparePath(pathname) == SUBDIR) {
|
|
// If so then we can start our search for the path, from the currently cached directory
|
|
#ifdef DEBUG
|
|
printf("Requested dir is a sub-dir of the cached directory,\n"
|
|
"so start search from current cached dir\n");
|
|
#endif
|
|
// if the cached chunk, is not the start of the dir,
|
|
// then we will need to re-load it before starting search
|
|
if (CachedDirInfo.cache_offset != 0) {
|
|
CachedDirInfo.cache_offset = 0;
|
|
CachedDirInfo.cache_size = CachedDirInfo.sector_num;
|
|
if (CachedDirInfo.cache_size > MAX_DIR_CACHE_SECTORS)
|
|
CachedDirInfo.cache_size = MAX_DIR_CACHE_SECTORS;
|
|
|
|
// Now fill the cache with the specified sectors
|
|
if (ReadSect(CachedDirInfo.sector_start + CachedDirInfo.cache_offset, CachedDirInfo.cache_size, CachedDirInfo.cache, &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from CD !\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = FALSE; // should we completely invalidate just because we couldnt read time?
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// start the search, with the path after the current directory
|
|
path_len = strlen(CachedDirInfo.pathname);
|
|
strcpy(dirname, pathname + path_len);
|
|
|
|
// FindPath should use the current directory cache to start it's search
|
|
// and should change CachedDirInfo.pathname, to the path of the dir it finds
|
|
// it should also cache the first chunk of directory sectors,
|
|
// and fill the contents of the other elements of CachedDirInfo appropriately
|
|
|
|
return (FindPath(dirname));
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we've got here, then either the cache was not valid to start with
|
|
// or the requested path is not a subdirectory of the currently cached directory
|
|
// so lets start again
|
|
#ifdef DEBUG
|
|
printf("The cache is not valid, or the requested directory is not a sub-dir of the cached one\n");
|
|
#endif
|
|
|
|
if (!isValidDisc()) {
|
|
#ifdef DEBUG
|
|
printf("No supported disc inserted.\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
sceCdDiskReady(0);
|
|
|
|
// Read the main volume descriptor
|
|
if (CDVD_GetVolumeDescriptor() != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Could not read the CD/DVD Volume Descriptor\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("Read the CD Volume Descriptor\n");
|
|
#endif
|
|
|
|
CachedDirInfo.path_depth = 0;
|
|
|
|
strcpy(CachedDirInfo.pathname, "");
|
|
|
|
// Setup the lba and sector size, for retrieving the root toc
|
|
CachedDirInfo.cache_offset = 0;
|
|
CachedDirInfo.sector_start = CDVolDesc.rootToc.tocLBA;
|
|
CachedDirInfo.sector_num = (CDVolDesc.rootToc.tocSize >> 11) + ((CDVolDesc.rootToc.tocSize & 2047) != 0);
|
|
|
|
CachedDirInfo.cache_size = CachedDirInfo.sector_num;
|
|
|
|
if (CachedDirInfo.cache_size > MAX_DIR_CACHE_SECTORS)
|
|
CachedDirInfo.cache_size = MAX_DIR_CACHE_SECTORS;
|
|
|
|
|
|
// Now fill the cache with the specified sectors
|
|
if (ReadSect(CachedDirInfo.sector_start + CachedDirInfo.cache_offset, CachedDirInfo.cache_size, CachedDirInfo.cache, &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from CD !\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = FALSE; // should we completely invalidate just because we couldnt read time?
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("Read the first block from the root directory\n");
|
|
#endif
|
|
|
|
// FindPath should use the current directory cache to start it's search (in this case the root)
|
|
// and should change CachedDirInfo.pathname, to the path of the dir it finds
|
|
// it should also cache the first chunk of directory sectors,
|
|
// and fill the contents of the other elements of CachedDirInfo appropriately
|
|
#ifdef DEBUG
|
|
printf("Calling FindPath\n");
|
|
#endif
|
|
strcpy(dirname, pathname);
|
|
|
|
return (FindPath(dirname));
|
|
}
|
|
|
|
int FindPath(char *pathname)
|
|
{
|
|
char *dirname;
|
|
char *seperator;
|
|
|
|
int dir_entry;
|
|
int found_dir;
|
|
|
|
struct dirTocEntry *tocEntryPointer;
|
|
struct TocEntry localTocEntry;
|
|
|
|
dirname = strtok(pathname, "\\/");
|
|
|
|
#ifdef DEBUG
|
|
printf("FindPath: trying to find directory %s\n", pathname);
|
|
#endif
|
|
|
|
if (!isValidDisc())
|
|
return FALSE;
|
|
|
|
sceCdDiskReady(0);
|
|
|
|
while (dirname != NULL) {
|
|
found_dir = FALSE;
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
|
|
// Always skip the first entry (self-refencing entry)
|
|
tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
|
|
|
|
dir_entry = 0;
|
|
|
|
for (; tocEntryPointer < (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048)); tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
|
|
// If we have a null toc entry, then we've either reached the end of the dir, or have reached a sector boundary
|
|
if (tocEntryPointer->length == 0) {
|
|
#ifdef DEBUG
|
|
printf("Got a null pointer entry, so either reached end of dir, or end of sector\n");
|
|
#endif
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)(CachedDirInfo.cache + (((((char *)tocEntryPointer - CachedDirInfo.cache) / 2048) + 1) * 2048));
|
|
}
|
|
|
|
if (tocEntryPointer >= (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048))) {
|
|
// If we've gone past the end of the cache
|
|
// then check if there are more sectors to load into the cache
|
|
|
|
if ((CachedDirInfo.cache_offset + CachedDirInfo.cache_size) < CachedDirInfo.sector_num) {
|
|
// If there are more sectors to load, then load them
|
|
CachedDirInfo.cache_offset += CachedDirInfo.cache_size;
|
|
CachedDirInfo.cache_size = CachedDirInfo.sector_num - CachedDirInfo.cache_offset;
|
|
|
|
if (CachedDirInfo.cache_size > MAX_DIR_CACHE_SECTORS)
|
|
CachedDirInfo.cache_size = MAX_DIR_CACHE_SECTORS;
|
|
|
|
if (ReadSect(CachedDirInfo.sector_start + CachedDirInfo.cache_offset, CachedDirInfo.cache_size, CachedDirInfo.cache, &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from CD !\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = FALSE; // should we completely invalidate just because we couldnt read time?
|
|
return FALSE;
|
|
}
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
} else {
|
|
CachedDirInfo.valid = FALSE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// If the toc Entry is a directory ...
|
|
if (tocEntryPointer->fileProperties & 0x02) {
|
|
// Convert to our format (inc ascii name), for the check
|
|
TocEntryCopy(&localTocEntry, tocEntryPointer);
|
|
|
|
// If it's the link to the parent directory, then give it the name ".."
|
|
if (dir_entry == 0) {
|
|
if (CachedDirInfo.path_depth != 0) {
|
|
#ifdef DEBUG
|
|
printf("First directory entry in dir, so name it '..'\n");
|
|
#endif
|
|
|
|
strcpy(localTocEntry.filename, "..");
|
|
}
|
|
}
|
|
|
|
// Check if this is the directory that we are looking for
|
|
if (strcasecmp(dirname, localTocEntry.filename) == 0) {
|
|
#ifdef DEBUG
|
|
printf("Found the matching sub-directory\n");
|
|
#endif
|
|
|
|
found_dir = TRUE;
|
|
|
|
if (dir_entry == 0) {
|
|
// We've matched with the parent directory
|
|
// so truncate the pathname by one level
|
|
|
|
if (CachedDirInfo.path_depth > 0)
|
|
CachedDirInfo.path_depth--;
|
|
|
|
if (CachedDirInfo.path_depth == 0) {
|
|
// If at root then just clear the path to root
|
|
// (simpler than finding the colon seperator etc)
|
|
CachedDirInfo.pathname[0] = 0;
|
|
} else {
|
|
seperator = strrchr(CachedDirInfo.pathname, '/');
|
|
|
|
if (seperator != NULL)
|
|
*seperator = 0;
|
|
}
|
|
} else {
|
|
// otherwise append a seperator, and the matched directory
|
|
// to the pathname
|
|
strcat(CachedDirInfo.pathname, "/");
|
|
|
|
#ifdef DEBUG
|
|
printf("Adding '%s' to cached pathname - path depth = %d\n", dirname, CachedDirInfo.path_depth);
|
|
#endif
|
|
|
|
strcat(CachedDirInfo.pathname, dirname);
|
|
|
|
CachedDirInfo.path_depth++;
|
|
}
|
|
|
|
// Exit out of the search loop
|
|
// (and find the next sub-directory, if there is one)
|
|
break;
|
|
} else {
|
|
#ifdef DEBUG
|
|
printf("Found a directory, but it doesn't match\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
dir_entry++;
|
|
|
|
} // end of cache block search loop
|
|
|
|
|
|
// if we've reached here, without finding the directory, then it's not there
|
|
if (found_dir != TRUE) {
|
|
CachedDirInfo.valid = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
// find name of next dir
|
|
dirname = strtok(NULL, "\\/");
|
|
|
|
CachedDirInfo.sector_start = localTocEntry.fileLBA;
|
|
CachedDirInfo.sector_num = (localTocEntry.fileSize >> 11) + ((CDVolDesc.rootToc.tocSize & 2047) != 0);
|
|
|
|
// Cache the start of the found directory
|
|
// (used in searching if this isn't the last dir,
|
|
// or used by whatever requested the cache in the first place if it is the last dir)
|
|
CachedDirInfo.cache_offset = 0;
|
|
CachedDirInfo.cache_size = CachedDirInfo.sector_num;
|
|
|
|
if (CachedDirInfo.cache_size > MAX_DIR_CACHE_SECTORS)
|
|
CachedDirInfo.cache_size = MAX_DIR_CACHE_SECTORS;
|
|
|
|
if (ReadSect(CachedDirInfo.sector_start + CachedDirInfo.cache_offset, CachedDirInfo.cache_size, CachedDirInfo.cache, &cdReadMode) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("Couldn't Read from CD, trying to read %d sectors, starting at sector %d !\n",
|
|
CachedDirInfo.cache_size, CachedDirInfo.sector_start + CachedDirInfo.cache_offset);
|
|
#endif
|
|
|
|
CachedDirInfo.valid = FALSE; // should we completely invalidate just because we couldnt read time?
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// If we've got here then we found the requested directory
|
|
#ifdef DEBUG
|
|
printf("FindPath found the path\n");
|
|
#endif
|
|
|
|
CachedDirInfo.valid = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
// This is the getdir for use by IOP clients
|
|
// fills an array of TocEntry stucts in IOP memory
|
|
int CDVD_getdir_IOP(const char *pathname, const char *extensions, enum CDVD_getMode getMode, struct TocEntry tocEntry[], unsigned int req_entries)
|
|
{
|
|
// TO DO
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// This is the getdir for use by the EE RPC client
|
|
// It DMA's entries to the specified buffer in EE memory
|
|
int CDVD_GetDir_RPC(const char *pathname, const char *extensions, enum CDVD_getMode getMode, struct TocEntry tocEntry[], unsigned int req_entries)
|
|
{
|
|
int matched_entries;
|
|
int dir_entry;
|
|
|
|
struct TocEntry localTocEntry;
|
|
|
|
struct dirTocEntry *tocEntryPointer;
|
|
|
|
int intStatus; // interrupt status - for dis/en-abling interrupts
|
|
|
|
struct t_SifDmaTransfer dmaStruct;
|
|
int dmaID;
|
|
|
|
dmaID = 0;
|
|
|
|
#ifdef DEBUG
|
|
printf("RPC GetDir Request\n");
|
|
#endif
|
|
|
|
matched_entries = 0;
|
|
|
|
// pre-cache the dir (and get the new pathname - in-case selected "..")
|
|
if (CDVD_Cache_Dir(pathname, CACHE_START) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_GetDir_RPC - Call of CDVD_Cache_Dir failed\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("requested directory is %d sectors\n", CachedDirInfo.sector_num);
|
|
#endif
|
|
|
|
if ((getMode == CDVD_GET_DIRS_ONLY) || (getMode == CDVD_GET_FILES_AND_DIRS)) {
|
|
// Cache the start of the requested directory
|
|
if (CDVD_Cache_Dir(CachedDirInfo.pathname, CACHE_START) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_GetDir_RPC - Call of CDVD_Cache_Dir failed\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
|
|
// skip the first self-referencing entry
|
|
tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
|
|
|
|
// skip the parent entry if this is the root
|
|
if (CachedDirInfo.path_depth == 0)
|
|
tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
|
|
|
|
dir_entry = 0;
|
|
|
|
while (1) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_GetDir_RPC - inside while-loop\n");
|
|
#endif
|
|
|
|
// parse the current cache block
|
|
for (; tocEntryPointer < (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048)); tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
|
|
if (tocEntryPointer->length == 0) {
|
|
// if we have a toc entry length of zero,
|
|
// then we've either reached the end of the sector, or the end of the dir
|
|
// so point to next sector (if there is one - will be checked by next condition)
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)(CachedDirInfo.cache + (((((char *)tocEntryPointer - CachedDirInfo.cache) / 2048) + 1) * 2048));
|
|
}
|
|
|
|
if (tocEntryPointer >= (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048))) {
|
|
// we've reached the end of the current cache block (which may be end of entire dir
|
|
// so just break the loop
|
|
break;
|
|
}
|
|
|
|
// Check if the current entry is a dir or a file
|
|
if (tocEntryPointer->fileProperties & 0x02) {
|
|
#ifdef DEBUG
|
|
printf("We found a dir, and we want all dirs\n");
|
|
#endif
|
|
|
|
// wait for any previous DMA to complete
|
|
// before over-writing localTocEntry
|
|
while (sceSifDmaStat(dmaID) >= 0)
|
|
;
|
|
|
|
TocEntryCopy(&localTocEntry, tocEntryPointer);
|
|
|
|
if (dir_entry == 0) {
|
|
if (CachedDirInfo.path_depth != 0) {
|
|
#ifdef DEBUG
|
|
printf("It's the first directory entry, so name it '..'\n");
|
|
#endif
|
|
|
|
strcpy(localTocEntry.filename, "..");
|
|
}
|
|
}
|
|
|
|
// DMA localTocEntry to the address specified by tocEntry[matched_entries]
|
|
|
|
// setup the dma struct
|
|
dmaStruct.src = &localTocEntry;
|
|
dmaStruct.dest = &tocEntry[matched_entries];
|
|
dmaStruct.size = sizeof(struct TocEntry);
|
|
dmaStruct.attr = 0;
|
|
|
|
// Do the DMA transfer
|
|
CpuSuspendIntr(&intStatus);
|
|
|
|
dmaID = sceSifSetDma(&dmaStruct, 1);
|
|
|
|
CpuResumeIntr(intStatus);
|
|
|
|
matched_entries++;
|
|
} else // it must be a file
|
|
{
|
|
#ifdef DEBUG
|
|
printf("We found a file, but we dont want files (at least not yet)\n");
|
|
#endif
|
|
}
|
|
|
|
dir_entry++;
|
|
|
|
if (matched_entries >= req_entries) // if we've filled the requested buffer
|
|
return (matched_entries); // then just return
|
|
|
|
} // end of the current cache block
|
|
|
|
// if there is more dir to load, then load next chunk, else finish
|
|
if ((CachedDirInfo.cache_offset + CachedDirInfo.cache_size) < CachedDirInfo.sector_num) {
|
|
if (CDVD_Cache_Dir(CachedDirInfo.pathname, CACHE_NEXT) != TRUE) {
|
|
// failed to cache next block (should return TRUE even if
|
|
// there is no more directory, as long as a CD read didnt fail
|
|
return -1;
|
|
}
|
|
} else
|
|
break;
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
}
|
|
}
|
|
|
|
// Next do files
|
|
if ((getMode == CDVD_GET_FILES_ONLY) || (getMode == CDVD_GET_FILES_AND_DIRS)) {
|
|
// Cache the start of the requested directory
|
|
if (CDVD_Cache_Dir(CachedDirInfo.pathname, CACHE_START) != TRUE) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_GetDir_RPC - Call of CDVD_Cache_Dir failed\n");
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
|
|
// skip the first self-referencing entry
|
|
tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
|
|
|
|
// skip the parent entry if this is the root
|
|
if (CachedDirInfo.path_depth == 0)
|
|
tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length);
|
|
|
|
dir_entry = 0;
|
|
|
|
while (1) {
|
|
#ifdef DEBUG
|
|
printf("CDVD_GetDir_RPC - inside while-loop\n");
|
|
#endif
|
|
|
|
// parse the current cache block
|
|
for (; tocEntryPointer < (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048)); tocEntryPointer = (struct dirTocEntry *)((u8 *)tocEntryPointer + tocEntryPointer->length)) {
|
|
if (tocEntryPointer->length == 0) {
|
|
// if we have a toc entry length of zero,
|
|
// then we've either reached the end of the sector, or the end of the dir
|
|
// so point to next sector (if there is one - will be checked by next condition)
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)(CachedDirInfo.cache + (((((char *)tocEntryPointer - CachedDirInfo.cache) / 2048) + 1) * 2048));
|
|
}
|
|
|
|
if (tocEntryPointer >= (struct dirTocEntry *)(CachedDirInfo.cache + (CachedDirInfo.cache_size * 2048))) {
|
|
// we've reached the end of the current cache block (which may be end of entire dir
|
|
// so just break the loop
|
|
break;
|
|
}
|
|
|
|
// Check if the current entry is a dir or a file
|
|
if (tocEntryPointer->fileProperties & 0x02) {
|
|
#ifdef DEBUG
|
|
printf("We don't want files now\n");
|
|
#endif
|
|
} else // it must be a file
|
|
{
|
|
// wait for any previous DMA to complete
|
|
// before over-writing localTocEntry
|
|
while (sceSifDmaStat(dmaID) >= 0)
|
|
;
|
|
|
|
TocEntryCopy(&localTocEntry, tocEntryPointer);
|
|
|
|
if (strlen(extensions) > 0) {
|
|
// check if the file matches the extension list
|
|
if (TocEntryCompare(localTocEntry.filename, extensions) == TRUE) {
|
|
#ifdef DEBUG
|
|
printf("We found a file that matches the requested extension list\n");
|
|
#endif
|
|
|
|
// DMA localTocEntry to the address specified by tocEntry[matched_entries]
|
|
|
|
// setup the dma struct
|
|
dmaStruct.src = &localTocEntry;
|
|
dmaStruct.dest = &tocEntry[matched_entries];
|
|
dmaStruct.size = sizeof(struct TocEntry);
|
|
dmaStruct.attr = 0;
|
|
|
|
// Do the DMA transfer
|
|
CpuSuspendIntr(&intStatus);
|
|
|
|
dmaID = sceSifSetDma(&dmaStruct, 1);
|
|
|
|
CpuResumeIntr(intStatus);
|
|
|
|
matched_entries++;
|
|
} else {
|
|
#ifdef DEBUG
|
|
printf("We found a file, but it didnt match the requested extension list\n");
|
|
#endif
|
|
}
|
|
} else // no extension list to match against
|
|
{
|
|
#ifdef DEBUG
|
|
printf("We found a file, and there is not extension list to match against\n");
|
|
#endif
|
|
|
|
// DMA localTocEntry to the address specified by tocEntry[matched_entries]
|
|
|
|
// setup the dma struct
|
|
dmaStruct.src = &localTocEntry;
|
|
dmaStruct.dest = &tocEntry[matched_entries];
|
|
dmaStruct.size = sizeof(struct TocEntry);
|
|
dmaStruct.attr = 0;
|
|
|
|
// Do the DMA transfer
|
|
CpuSuspendIntr(&intStatus);
|
|
|
|
dmaID = sceSifSetDma(&dmaStruct, 1);
|
|
|
|
CpuResumeIntr(intStatus);
|
|
|
|
matched_entries++;
|
|
}
|
|
}
|
|
|
|
dir_entry++;
|
|
|
|
if (matched_entries >= req_entries) // if we've filled the requested buffer
|
|
return (matched_entries); // then just return
|
|
|
|
} // end of the current cache block
|
|
|
|
|
|
// if there is more dir to load, then load next chunk, else finish
|
|
if ((CachedDirInfo.cache_offset + CachedDirInfo.cache_size) < CachedDirInfo.sector_num) {
|
|
if (CDVD_Cache_Dir(CachedDirInfo.pathname, CACHE_NEXT) != TRUE) {
|
|
// failed to cache next block (should return TRUE even if
|
|
// there is no more directory, as long as a CD read didnt fail
|
|
return -1;
|
|
}
|
|
} else
|
|
break;
|
|
|
|
tocEntryPointer = (struct dirTocEntry *)CachedDirInfo.cache;
|
|
}
|
|
}
|
|
// reached the end of the dir, before filling up the requested entries
|
|
|
|
return (matched_entries);
|
|
}
|
|
|
|
int CdFlushCache(void)
|
|
{
|
|
strcpy(CachedDirInfo.pathname, ""); // The pathname of the cached directory
|
|
CachedDirInfo.valid = FALSE; // Cache is not valid
|
|
CachedDirInfo.path_depth = 0; // 0 = root)
|
|
CachedDirInfo.sector_start = 0; // The start sector (LBA) of the cached directory
|
|
CachedDirInfo.sector_num = 0; // The total size of the directory (in sectors)
|
|
CachedDirInfo.cache_offset = 0; // The offset from sector_start of the cached area
|
|
CachedDirInfo.cache_size = 0; // The size of the cached directory area (in sectors)
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
unsigned int CdGetSize(void)
|
|
{
|
|
if (CDVD_GetVolumeDescriptor() != TRUE)
|
|
return TRUE;
|
|
|
|
return CDVolDesc.volSize;
|
|
}
|
|
|
|
void *CDVDRpc_FlushCache()
|
|
{
|
|
CdFlushCache();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void *CDVDRpc_Stop()
|
|
{
|
|
if (isValidDisc()) {
|
|
sceCdStop();
|
|
sceCdSync(0);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Send: Offset 0 = mode. Size = int
|
|
// Return: Offset 0 = traycnt. Size = int
|
|
void *CDVDRpc_TrayReq(unsigned int *sbuff)
|
|
{
|
|
int ret;
|
|
|
|
sceCdTrayReq(sbuff[0], (int *)&ret);
|
|
|
|
sbuff[0] = ret;
|
|
return sbuff;
|
|
}
|
|
|
|
// Send: Offset 0 = mode
|
|
// Return: Offset 0 = ret val (cd status)
|
|
void *CDVDRpc_DiskReady(unsigned int *sbuff)
|
|
{
|
|
int ret;
|
|
|
|
if (isValidDisc())
|
|
ret = sceCdDiskReady(sbuff[0]);
|
|
else
|
|
ret = -1;
|
|
|
|
sbuff[0] = ret;
|
|
return sbuff;
|
|
}
|
|
|
|
// Send: Offset 0 = filename string (1024 bytes)
|
|
// Return: Offset 0 = ret val (true/false). Size = int
|
|
// Offset 1024 = start of TocEntry structure
|
|
void *CDVDRpc_FindFile(unsigned int *sbuff)
|
|
{
|
|
int ret;
|
|
|
|
ret = CDVD_findfile((char *)&sbuff[0], (struct TocEntry *)&sbuff[1024 / 4]);
|
|
|
|
sbuff[0] = ret;
|
|
|
|
return sbuff;
|
|
}
|
|
|
|
// Send: Offset 0 = filename string (1024 bytes)
|
|
// Send: Offset 1024 = extension string (128 bytes)
|
|
// Send: Offset 1152 = CDVD_getMode
|
|
// Send: Offset 1156 = pointer to array of TocEntry structures in EE mem
|
|
// Send: Offset 1160 = requested number of entries
|
|
|
|
// Return: Offset 0 = ret val (number of matched entries). Size = int
|
|
// Return: Offset 4 = updated pathname (for if path selected = ".."
|
|
void *CDVDRpc_Getdir(unsigned int *sbuff)
|
|
{
|
|
int ret;
|
|
|
|
ret = CDVD_GetDir_RPC(
|
|
(char *)&sbuff[0 / 4], // pathname string
|
|
(char *)&sbuff[1024 / 4], // extension string
|
|
sbuff[1152 / 4], // CDVD_getMode
|
|
(struct TocEntry *)sbuff[1156 / 4], // pointer to array of TocEntry structures in EE mem
|
|
sbuff[1160 / 4] // requested number of entries
|
|
);
|
|
|
|
sbuff[0] = ret;
|
|
strcpy((char *)&sbuff[1], CachedDirInfo.pathname);
|
|
return sbuff;
|
|
}
|
|
|
|
void *CDVDRpc_GetSize(unsigned int *sbuff)
|
|
{
|
|
sbuff[0] = CdGetSize();
|
|
return sbuff;
|
|
}
|
|
|
|
/*************************************************
|
|
* The functions below are for internal use only, *
|
|
* and are not to be exported *
|
|
*************************************************/
|
|
|
|
void CDVD_Thread(void *param)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("CDVD: RPC Initialize\n");
|
|
#endif
|
|
|
|
sceSifInitRpc(0);
|
|
|
|
// 0x4800 bytes for TocEntry structures (can fit 128 of them)
|
|
// 0x400 bytes for the filename string
|
|
buffer = AllocSysMemory(0, 0x4C00, NULL);
|
|
if (buffer == NULL) {
|
|
#ifdef DEBUG
|
|
printf("Failed to allocate memory for RPC buffer!\n");
|
|
#endif
|
|
|
|
SleepThread();
|
|
}
|
|
|
|
sceSifSetRpcQueue(&qd, GetThreadId());
|
|
sceSifRegisterRpc(&sd0, CDVD_IRX, CDVD_rpc_server, (void *)buffer, 0, 0, &qd);
|
|
sceSifRpcLoop(&qd);
|
|
}
|
|
|
|
void *CDVD_rpc_server(int fno, void *data, int size)
|
|
{
|
|
|
|
switch (fno) {
|
|
case CDVD_FINDFILE:
|
|
return CDVDRpc_FindFile((unsigned *)data);
|
|
case CDVD_GETDIR:
|
|
return CDVDRpc_Getdir((unsigned *)data);
|
|
case CDVD_STOP:
|
|
return CDVDRpc_Stop();
|
|
case CDVD_TRAYREQ:
|
|
return CDVDRpc_TrayReq((unsigned *)data);
|
|
case CDVD_DISKREADY:
|
|
return CDVDRpc_DiskReady((unsigned *)data);
|
|
case CDVD_FLUSHCACHE:
|
|
return CDVDRpc_FlushCache();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void _splitpath(const char *constpath, char *dir, char *fname)
|
|
{
|
|
// 255 char max path-length is an ISO9660 restriction
|
|
// we must change this for Joliet or relaxed iso restriction support
|
|
static char pathcopy[1024 + 1];
|
|
|
|
char *slash;
|
|
|
|
strncpy(pathcopy, constpath, 1024);
|
|
|
|
slash = strrchr(pathcopy, '/');
|
|
|
|
// if the path doesn't contain a '/' then look for a '\'
|
|
if (!slash)
|
|
slash = strrchr(pathcopy, (int)'\\');
|
|
|
|
// if a slash was found
|
|
if (slash != NULL) {
|
|
// null terminate the path
|
|
slash[0] = 0;
|
|
// and copy the path into 'dir'
|
|
strncpy(dir, pathcopy, 1024);
|
|
dir[255] = 0;
|
|
|
|
// copy the filename into 'fname'
|
|
strncpy(fname, slash + 1, 128);
|
|
fname[128] = 0;
|
|
} else {
|
|
dir[0] = 0;
|
|
|
|
strncpy(fname, pathcopy, 128);
|
|
fname[128] = 0;
|
|
}
|
|
}
|
|
|
|
// Copy a TOC Entry from the CD native format to our tidier format
|
|
void TocEntryCopy(struct TocEntry *tocEntry, struct dirTocEntry *internalTocEntry)
|
|
{
|
|
int i;
|
|
int filenamelen;
|
|
|
|
tocEntry->fileSize = internalTocEntry->fileSize;
|
|
tocEntry->fileLBA = internalTocEntry->fileLBA;
|
|
tocEntry->fileProperties = internalTocEntry->fileProperties;
|
|
|
|
if (CDVolDesc.filesystemType == 2) {
|
|
// This is a Joliet Filesystem, so use Unicode to ISO string copy
|
|
filenamelen = internalTocEntry->filenameLength / 2;
|
|
|
|
for (i = 0; i < filenamelen; i++)
|
|
tocEntry->filename[i] = internalTocEntry->filename[(i << 1) + 1];
|
|
} else {
|
|
filenamelen = internalTocEntry->filenameLength;
|
|
|
|
// use normal string copy
|
|
strncpy(tocEntry->filename, internalTocEntry->filename, 128);
|
|
}
|
|
|
|
tocEntry->filename[filenamelen] = 0;
|
|
|
|
if (!(tocEntry->fileProperties & 0x02)) {
|
|
// strip the ;1 from the filename (if it's there)
|
|
strtok(tocEntry->filename, ";");
|
|
}
|
|
}
|
|
|
|
// Check if a TOC Entry matches our extension list
|
|
int TocEntryCompare(char *filename, const char *extensions)
|
|
{
|
|
static char ext_list[129];
|
|
|
|
char *token;
|
|
|
|
char *ext_point;
|
|
|
|
strncpy(ext_list, extensions, 128);
|
|
ext_list[128] = 0;
|
|
|
|
token = strtok(ext_list, " ,");
|
|
while (token != NULL) {
|
|
// if 'token' matches extension of 'filename'
|
|
// then return a match
|
|
ext_point = strrchr(filename, '.');
|
|
|
|
if (strcasecmp(ext_point, token) == 0)
|
|
return (TRUE);
|
|
|
|
/* Get next token: */
|
|
token = strtok(NULL, " ,");
|
|
}
|
|
|
|
// If not match found then return FALSE
|
|
return (FALSE);
|
|
}
|
|
|
|
// Used in findfile
|
|
//int tolower(int c);
|
|
int strcasecmp(const char *s1, const char *s2)
|
|
{
|
|
while (*s1 != '\0' && tolower(*s1) == tolower(*s2)) {
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return tolower(*(unsigned char *)s1) - tolower(*(unsigned char *)s2);
|
|
}
|
|
|
|
int strncasecmp(const char *s1, const char *s2, int limit)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < limit; i++) {
|
|
if (*s1 == '\0')
|
|
return tolower(*(unsigned char *)s1) - tolower(*(unsigned char *)s2);
|
|
|
|
if (tolower(*s1) != tolower(*s2))
|
|
return tolower(*(unsigned char *)s1) - tolower(*(unsigned char *)s2);
|
|
|
|
s1++;
|
|
s2++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
enum PathMatch ComparePath(const char *path)
|
|
{
|
|
int length;
|
|
int i;
|
|
|
|
length = strlen(CachedDirInfo.pathname);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
// check if character matches
|
|
if (path[i] != CachedDirInfo.pathname[i]) {
|
|
// if not, then is it just because of different path seperator ?
|
|
if ((path[i] == '/') || (path[i] == '\\')) {
|
|
if ((CachedDirInfo.pathname[i] == '/') || (CachedDirInfo.pathname[i] == '\\')) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// if the characters don't match for any other reason then report a failure
|
|
return NOT_MATCH;
|
|
}
|
|
}
|
|
|
|
// Reached the end of the Cached pathname
|
|
|
|
// if requested path is same length, then report exact match
|
|
if (path[length] == 0)
|
|
return MATCH;
|
|
|
|
// if requested path is longer, and next char is a dir seperator
|
|
// then report sub-dir match
|
|
if ((path[length] == '/') || (path[length] == '\\'))
|
|
return SUBDIR;
|
|
else
|
|
return NOT_MATCH;
|
|
}
|