pcsx2/plugins/CDVDiso/src/CDVDisop.cpp

559 lines
10 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <stdarg.h>
#include "CDVDiso.h"
#include "Config.h"
#ifndef MAX_PATH
#define MAX_PATH 255
#endif
char IsoFile[256];
char IsoCWD[256];
char CdDev[256];
_cdIso cdIso[8];
u8 *pbuffer;
int cdblocksize;
int cdblockofs;
int cdoffset;
int cdtype;
int cdblocks;
int Zmode; // 1 Z - 2 bz2
int fmode; // 0 - file / 1 - Zfile
char *Ztable;
int BlockDump;
isoFile *fdump;
isoFile *iso;
FILE *cdvdLog = NULL;
// This var is used to detect resume-style behavior of the Pcsx2 emulator,
// and skip prompting the user for a new CD when it's likely they want to run the existing one.
static char cdvdCurrentIso[MAX_PATH];
char *methods[] =
{
".Z - compress faster",
".BZ - compress better",
NULL
};
#ifdef PCSX2_DEBUG
char *LibName = "Linuz Iso CDVD (Debug) ";
#else
char *LibName = "Linuz Iso CDVD ";
#endif
const u8 version = PS2E_CDVD_VERSION;
const u8 revision = 0;
const u8 build = 9;
u8 cdbuffer[CD_FRAMESIZE_RAW * 10] = {0};
s32 msf_to_lba(u8 m, u8 s, u8 f)
{
u32 lsn;
lsn = f;
lsn += (s - 2) * 75;
lsn += m * 75 * 60;
return lsn;
}
void lba_to_msf(s32 lba, u8* m, u8* s, u8* f)
{
lba += 150;
*m = lba / (60 * 75);
*s = (lba / 75) % 60;
*f = lba % 75;
}
#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */
#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */
EXPORT_C_(char*) PS2EgetLibName()
{
return LibName;
}
EXPORT_C_(u32) PS2EgetLibType()
{
return PS2E_LT_CDVD;
}
EXPORT_C_(u32) PS2EgetLibVersion2(u32 type)
{
return (version << 16) | (revision << 8) | build;
}
#ifdef PCSX2_DEBUG
void __Log(char *fmt, ...)
{
va_list list;
if (cdvdLog == NULL) return;
va_start(list, fmt);
vfprintf(cdvdLog, fmt, list);
va_end(list);
}
#else
#define __Log 0&&
#endif
EXPORT_C_(s32) CDVDinit()
{
#ifdef PCSX2_DEBUG
cdvdLog = fopen("logs/cdvdLog.txt", "w");
if (cdvdLog == NULL)
{
cdvdLog = fopen("cdvdLog.txt", "w");
if (cdvdLog == NULL)
{
SysMessage("Can't create cdvdLog.txt");
return -1;
}
}
setvbuf(cdvdLog, NULL, _IONBF, 0);
CDVD_LOG("CDVDinit\n");
#endif
cdvdCurrentIso[0] = 0;
memset(cdIso, 0, sizeof(cdIso));
return 0;
}
EXPORT_C_(void) CDVDshutdown()
{
cdvdCurrentIso[0] = 0;
#ifdef CDVD_LOG
if (cdvdLog != NULL) fclose(cdvdLog);
#endif
}
EXPORT_C_(s32) CDVDopen(const char* pTitle)
{
LoadConf();
if (pTitle != NULL) strcpy(IsoFile, pTitle);
if (*IsoFile == 0) strcpy(IsoFile, cdvdCurrentIso);
if (*IsoFile == 0)
{
char temp[256];
CfgOpenFile();
if (IsoFile[0] == 0)
{
// user pressed CANCEL
return 1;
}
strcpy(temp, IsoFile);
*IsoFile = 0;
SaveConf();
strcpy(IsoFile, temp);
}
iso = isoOpen(IsoFile);
if (iso == NULL)
{
SysMessage("Error loading %s\nMake sure the iso file is not mounted in any disk emulation software!", IsoFile);
return -1;
}
if (iso->type == ISOTYPE_DVD)
cdtype = CDVD_TYPE_PS2DVD;
else if (iso->type == ISOTYPE_AUDIO)
cdtype = CDVD_TYPE_CDDA;
else
cdtype = CDVD_TYPE_PS2CD;
if (BlockDump)
{
char fname_only[MAX_PATH];
#ifdef _WIN32
char fname[MAX_PATH], ext[MAX_PATH];
_splitpath(IsoFile, NULL, NULL, fname, ext);
_makepath(fname_only, NULL, NULL, fname, NULL);
#else
char* p, *plast;
plast = p = strchr(IsoFile, '/');
while (p != NULL)
{
plast = p;
p = strchr(p + 1, '/');
}
// Lets not create dumps in the plugin directory.
strcpy(fname_only, "../");
if (plast != NULL)
strcat(fname_only, plast + 1);
else
strcat(fname_only, IsoFile);
plast = p = strchr(fname_only, '.');
while (p != NULL)
{
plast = p;
p = strchr(p + 1, '.');
}
if (plast != NULL) *plast = 0;
#endif
strcat(fname_only, ".dump");
fdump = isoCreate(fname_only, ISOFLAGS_BLOCKDUMP);
if (fdump) isoSetFormat(fdump, iso->blockofs, iso->blocksize, iso->blocks);
}
else
{
fdump = NULL;
}
return 0;
}
EXPORT_C_(void) CDVDclose()
{
if (!iso) return;
strcpy(cdvdCurrentIso, IsoFile);
isoClose(iso);
if (fdump != NULL) isoClose(fdump);
}
EXPORT_C_(s32) CDVDreadSubQ(u32 lsn, cdvdSubQ* subq)
{
if (!iso) return -1;
// fake it
u8 min, sec, frm;
subq->ctrl = 4;
subq->mode = 1;
subq->trackNum = itob(1);
subq->trackIndex = itob(1);
lba_to_msf(lsn, &min, &sec, &frm);
subq->trackM = itob(min);
subq->trackS = itob(sec);
subq->trackF = itob(frm);
subq->pad = 0;
lba_to_msf(lsn + (2*75), &min, &sec, &frm);
subq->discM = itob(min);
subq->discS = itob(sec);
subq->discF = itob(frm);
return 0;
}
EXPORT_C_(s32) CDVDgetTN(cdvdTN *Buffer)
{
Buffer->strack = 1;
Buffer->etrack = 1;
return 0;
}
EXPORT_C_(s32) CDVDgetTD(u8 Track, cdvdTD *Buffer)
{
if (!iso) return -1;
if (Track == 0)
{
Buffer->lsn = iso->blocks;
}
else
{
Buffer->type = CDVD_MODE1_TRACK;
Buffer->lsn = 0;
}
return 0;
}
static s32 layer1start = -1;
static bool testForPartitionInfo( const u8 (&tempbuffer)[CD_FRAMESIZE_RAW] )
{
const int off = iso->blockofs;
// test for: CD001
return (
(tempbuffer[off+1] == 0x43) &&
(tempbuffer[off+2] == 0x44) &&
(tempbuffer[off+3] == 0x30) &&
(tempbuffer[off+4] == 0x30) &&
(tempbuffer[off+5] == 0x31)
);
}
EXPORT_C_(s32) CDVDgetTOC(void* toc)
{
if (!iso) return -1;
u8 type = CDVDgetDiskType();
u8* tocBuff = (u8*)toc;
//__Log("CDVDgetTOC\n");
if (type == CDVD_TYPE_DVDV || type == CDVD_TYPE_PS2DVD)
{
// get dvd structure format
// scsi command 0x43
memset(tocBuff, 0, 2048);
if (layer1start != -2 && iso->blocks >= 0x300000)
{
int off = iso->blockofs;
// dual sided
tocBuff[ 0] = 0x24;
tocBuff[ 1] = 0x02;
tocBuff[ 2] = 0xF2;
tocBuff[ 3] = 0x00;
tocBuff[ 4] = 0x41;
tocBuff[ 5] = 0x95;
tocBuff[14] = 0x60; // dual sided, ptp
tocBuff[16] = 0x00;
tocBuff[17] = 0x03;
tocBuff[18] = 0x00;
tocBuff[19] = 0x00;
// search for it
if (layer1start == -1)
{
printf("CDVD: searching for layer1...");
/*tempbuffer = (u8*)malloc(CD_FRAMESIZE_RAW * 10);
for (layer1start = (iso->blocks / 2 - 0x10) & ~0xf; layer1start < 0x200010; layer1start += 16)
{
isoReadBlock(iso, tempbuffer, layer1start);
// CD001
if (tempbuffer[off+1] == 0x43 &&
tempbuffer[off+2] == 0x44 &&
tempbuffer[off+3] == 0x30 &&
tempbuffer[off+4] == 0x30 &&
tempbuffer[off+5] == 0x31)
break;
}
free(tempbuffer);*/
uint midsector = (iso->blocks / 2) & ~0xf;
uint deviation = 0;
while( (layer1start == -1) && (deviation < midsector-16) )
{
u8 tempbuffer[CD_FRAMESIZE_RAW];
isoReadBlock(iso, tempbuffer, midsector-deviation);
if(testForPartitionInfo( tempbuffer ))
layer1start = midsector-deviation;
else
{
isoReadBlock(iso, tempbuffer, midsector+deviation);
if( testForPartitionInfo( tempbuffer ) )
layer1start = midsector+deviation;
}
if( layer1start != -1 )
{
if( tempbuffer[iso->blockofs] != 0x01 )
{
fprintf( stderr, "(LinuzCDVDiso): Invalid partition type on layer 1!? (type=0x%x)", tempbuffer[iso->blockofs] );
}
}
deviation += 16;
}
if (layer1start == -1)
{
printf("(LinuzCDVDiso): Couldn't find second layer on dual layer... ignoring\n");
// fake it
tocBuff[ 0] = 0x04;
tocBuff[ 1] = 0x02;
tocBuff[ 2] = 0xF2;
tocBuff[ 3] = 0x00;
tocBuff[ 4] = 0x86;
tocBuff[ 5] = 0x72;
tocBuff[16] = 0x00;
tocBuff[17] = 0x03;
tocBuff[18] = 0x00;
tocBuff[19] = 0x00;
layer1start = -2;
return 0;
}
printf("(LinuzCDVDiso): found at 0x%8.8x\n", layer1start);
layer1start = layer1start + 0x30000 - 1;
}
tocBuff[20] = layer1start >> 24;
tocBuff[21] = (layer1start >> 16) & 0xff;
tocBuff[22] = (layer1start >> 8) & 0xff;
tocBuff[23] = (layer1start >> 0) & 0xff;
}
else
{
// fake it
tocBuff[ 0] = 0x04;
tocBuff[ 1] = 0x02;
tocBuff[ 2] = 0xF2;
tocBuff[ 3] = 0x00;
tocBuff[ 4] = 0x86;
tocBuff[ 5] = 0x72;
tocBuff[16] = 0x00;
tocBuff[17] = 0x03;
tocBuff[18] = 0x00;
tocBuff[19] = 0x00;
}
}
else if ((type == CDVD_TYPE_CDDA) || (type == CDVD_TYPE_PS2CDDA) ||
(type == CDVD_TYPE_PS2CD) || (type == CDVD_TYPE_PSCDDA) || (type == CDVD_TYPE_PSCD))
{
// cd toc
// (could be replaced by 1 command that reads the full toc)
u8 min, sec, frm;
s32 i, err;
cdvdTN diskInfo;
cdvdTD trackInfo;
memset(tocBuff, 0, 1024);
if (CDVDgetTN(&diskInfo) == -1)
{
diskInfo.etrack = 0;
diskInfo.strack = 1;
}
if (CDVDgetTD(0, &trackInfo) == -1) trackInfo.lsn = 0;
tocBuff[0] = 0x41;
tocBuff[1] = 0x00;
//Number of FirstTrack
tocBuff[2] = 0xA0;
tocBuff[7] = itob(diskInfo.strack);
//Number of LastTrack
tocBuff[12] = 0xA1;
tocBuff[17] = itob(diskInfo.etrack);
//DiskLength
lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
tocBuff[22] = 0xA2;
tocBuff[27] = itob(min);
tocBuff[28] = itob(sec);
for (i = diskInfo.strack; i <= diskInfo.etrack; i++)
{
err = CDVDgetTD(i, &trackInfo);
lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
tocBuff[i*10+30] = trackInfo.type;
tocBuff[i*10+32] = err == -1 ? 0 : itob(i); //number
tocBuff[i*10+37] = itob(min);
tocBuff[i*10+38] = itob(sec);
tocBuff[i*10+39] = itob(frm);
}
}
else
return -1;
return 0;
}
EXPORT_C_(s32) CDVDreadTrack(u32 lsn, int mode)
{
if (!iso) return -1;
int _lsn = lsn;
//__Log("CDVDreadTrack: %x %x\n", lsn, mode);
if (_lsn < 0)
{
// lsn = 2097152 + (-_lsn);
lsn = iso->blocks - (-_lsn);
}
// printf ("CDRreadTrack %d\n", lsn);
isoReadBlock(iso, cdbuffer, lsn);
if (fdump != NULL)
{
isoWriteBlock(fdump, cdbuffer, lsn);
}
pbuffer = cdbuffer;
switch (mode)
{
case CDVD_MODE_2352:
break;
case CDVD_MODE_2340:
pbuffer += 12;
break;
case CDVD_MODE_2328:
pbuffer += 24;
break;
case CDVD_MODE_2048:
pbuffer += 24;
break;
}
return 0;
}
EXPORT_C_(u8*) CDVDgetBuffer()
{
return pbuffer;
}
EXPORT_C_(s32) CDVDgetDiskType()
{
return cdtype;
}
EXPORT_C_(s32) CDVDgetTrayStatus()
{
return CDVD_TRAY_CLOSE;
}
EXPORT_C_(s32) CDVDctrlTrayOpen()
{
return 0;
}
EXPORT_C_(s32) CDVDctrlTrayClose()
{
return 0;
}
EXPORT_C_(s32) CDVDtest()
{
if (*IsoFile == 0) return 0;
iso = isoOpen(IsoFile);
if (iso == NULL) return -1;
isoClose(iso);
return 0;
}