pcsx2/Misc.c

817 lines
20 KiB
C

/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2003 Pcsx2 Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/stat.h>
#include <ctype.h>
#include "Common.h"
#include "PsxCommon.h"
#include "CDVDisodrv.h"
#include "VUmicro.h"
#ifdef __WIN32__
#include "RDebug/deci2.h"
#endif
DWORD dwSaveVersion = 0x7a30000c;
extern u32 s_iLastCOP0Cycle;
extern int g_psxWriteOk;
PcsxConfig Config;
u32 BiosVersion;
char CdromId[12];
char *LabelAuthors = { N_(
"PCSX2 a PS2 emulator\n\n"
"written by:\n"
"saqib, refraction, zerofrog,\n"
"shadow, linuzappz, florin,\n"
"nachbrenner, auMatt, loser, \n"
"alexey silinov, goldfinger,\n"
"\n"
"Webmasters: CKemu, Falcon4ever")
};
char *LabelGreets = { N_(
"Greets to: Bobbi, Keith, CpUMasteR, Nave, Snake785, Raziel\n"
"Special thanks to: Sjeep, Dreamtime, F|RES, BGnome, MrBrown, \n"
"Seta-San, Skarmeth, blackd_wd, _Demo_\n"
"\n"
"Credits: Hiryu && Sjeep for their libcdvd (iso parsing and filesystem driver code)\n"
"\n"
"Some betatester/support dudes: Belmont, bositman, ChaosCode, CKemu, crushtest,"
"falcon4ever, GeneralPlot, jegHegy, parotaku, Prafull, Razorblade, Rudy_X, Seta-san")
};
static struct {
char *name;
u32 size;
} ioprps[]={
{"IOPRP14", 43845},
{"IOPRP142", 48109},
{"IOPRP143", 58317},
{"IOPRP144", 58525},
{"IOPRP15", 82741},
{"IOPRP151", 82917},
{"IOPRP153", 82949},
{"IOPRP16", 91909},
{"IOPRP165", 98901},
{"IOPRP20", 109809},
{"IOPRP202", 110993},
{"IOPRP205", 119797},
{"IOPRP21", 126857},
{"IOPRP211", 129577},
{"IOPRP213", 129577},
{"IOPRP214", 140945},
{"IOPRP22", 199257},
{"IOPRP221", 196937},
{"IOPRP222", 198233},
{"IOPRP224", 201065},
{"IOPRP23", 230329},
{"IOPRP234", 247641},
{"IOPRP24", 251065},
{"IOPRP241", 251049},
{"IOPRP242", 252409},
{"IOPRP243", 253201},
{"IOPRP250", 264897},
{"IOPRP252", 265233},
{"IOPRP253", 267217},
{"IOPRP254", 264449},
{"IOPRP255", 264449},
{"IOPRP260", 248945},
{"IOPRP270", 249121},
{"IOPRP271", 266817},
{"IOPRP280", 269889},
{"IOPRP300", 275345},
{"DNAS280", 272753},
{"DNAS270", 251729},
{"DNAS271", 268977},
{"DNAS300", 278641},
{"DNAS280", 272705},
{"DNAS255", 264945},
{NULL, 0}
};
void GetRPCVersion(char *ioprp, char *rpcver){
char *p=ioprp; int i;
struct TocEntry te;
if (p && (CDVD_findfile(p+strlen("cdromN:"), &te) != -1)){
for (i=0; ioprps[i].size>0; i++)
if (te.fileSize==ioprps[i].size)
break;
if (ioprps[i].size>0)
p=ioprps[i].name;
}
if (p && (p=strstr(p, "IOPRP")+strlen("IOPRP"))){
for (i=0;(i<4) && p && (*p>='0') && (*p<='9');i++, p++) rpcver[i]=*p;
for ( ; i<4 ;i++ ) rpcver[i]='0';
}
}
u32 GetBiosVersion() {
unsigned int fileOffset=0;
char *ROMVER;
char vermaj[8];
char vermin[8];
struct romdir *rd;
u32 version;
int i;
for (i=0; i<512*1024; i++) {
rd = (struct romdir*)&psRu8(i);
if (strncmp(rd->fileName, "RESET", 5) == 0)
break; /* found romdir */
}
if (i == 512*1024) return -1;
while(strlen(rd->fileName) > 0){
if (strcmp(rd->fileName, "ROMVER") == 0){ // found romver
ROMVER = &psRu8(fileOffset);
strncpy(vermaj, ROMVER+ 0, 2); vermaj[2] = 0;
strncpy(vermin, ROMVER+ 2, 2); vermin[2] = 0;
version = strtol(vermaj, (char**)NULL, 0) << 8;
version|= strtol(vermin, (char**)NULL, 0);
return version;
}
if ((rd->fileSize % 0x10)==0)
fileOffset += rd->fileSize;
else
fileOffset += (rd->fileSize + 0x10) & 0xfffffff0;
rd++;
}
return -1;
}
//2002-09-22 (Florin)
int IsBIOS(char *filename, char *description){
struct stat buf;
char Bios[260], ROMVER[14+1], zone[12+1];
FILE *fp;
unsigned int fileOffset=0, found=FALSE;
struct romdir rd;
strcpy(Bios, Config.BiosDir);
strcat(Bios, filename);
if (stat(Bios, &buf) == -1) return FALSE;
fp = fopen(Bios, "rb");
if (fp == NULL) return FALSE;
while ((ftell(fp)<512*1024) && (fread(&rd, DIRENTRY_SIZE, 1, fp)==1))
if (strcmp(rd.fileName, "RESET") == 0)
break; /* found romdir */
if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) {
fclose(fp);
return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img
}
while(strlen(rd.fileName) > 0){
if (strcmp(rd.fileName, "ROMVER") == 0){ // found romver
unsigned int filepos=ftell(fp);
fseek(fp, fileOffset, SEEK_SET);
if (fread(&ROMVER, 14, 1, fp) == 0) break;
fseek(fp, filepos, SEEK_SET);//go back
switch(ROMVER[4]){
case 'T':sprintf(zone, "T10K "); break;
case 'X':sprintf(zone, "Test ");break;
case 'J':sprintf(zone, "Japan "); break;
case 'A':sprintf(zone, "USA "); break;
case 'E':sprintf(zone, "Europe"); break;
case 'H':sprintf(zone, "HK "); break;
case 'P':sprintf(zone, "Free "); break;
case 'C':sprintf(zone, "China "); break;
default: sprintf(zone, "%c ",ROMVER[4]); break;//shoudn't show
}
sprintf(description, "%s vXX.XX(XX/XX/XXXX) %s", zone,
ROMVER[5]=='C'?"Console":ROMVER[5]=='D'?"Devel":"");
strncpy(description+ 8, ROMVER+ 0, 2);//ver major
strncpy(description+11, ROMVER+ 2, 2);//ver minor
strncpy(description+14, ROMVER+12, 2);//day
strncpy(description+17, ROMVER+10, 2);//month
strncpy(description+20, ROMVER+ 6, 4);//year
found = TRUE;
}
if ((rd.fileSize % 0x10)==0)
fileOffset += rd.fileSize;
else
fileOffset += (rd.fileSize + 0x10) & 0xfffffff0;
if (fread(&rd, DIRENTRY_SIZE, 1, fp)==0) break;
}
fileOffset-=((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize;
fclose(fp);
if (found) {
char percent[6];
if (buf.st_size<(int)fileOffset){
sprintf(percent, " %d%%", buf.st_size*100/(int)fileOffset);
strcat(description, percent);//we force users to have correct bioses,
//not that lame scph10000 of 513KB ;-)
}
return TRUE;
}
return FALSE; //fail quietly
}
// LOAD STUFF
#define ISODCL(from, to) (to - from + 1)
struct iso_directory_record {
char length [ISODCL (1, 1)]; /* 711 */
char ext_attr_length [ISODCL (2, 2)]; /* 711 */
char extent [ISODCL (3, 10)]; /* 733 */
char size [ISODCL (11, 18)]; /* 733 */
char date [ISODCL (19, 25)]; /* 7 by 711 */
char flags [ISODCL (26, 26)];
char file_unit_size [ISODCL (27, 27)]; /* 711 */
char interleave [ISODCL (28, 28)]; /* 711 */
char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
unsigned char name_len [ISODCL (33, 33)]; /* 711 */
char name [1];
};
#define READTRACK(lsn) \
if (CDVDreadTrack(lsn, CDVD_MODE_2352) == -1) return -1; \
buf = CDVDgetBuffer(); if (buf == NULL) return -1;
int LoadCdrom() {
return 0;
}
int CheckCdrom() {
u8 *buf;
READTRACK(16);
strncpy(CdromId, buf+52, 10);
return 0;
}
int GetPS2ElfName(char *name){
FILE *fp;
int f;
char buffer[256];//if a file is longer...it should be shorter :D
char *pos;
static struct TocEntry tocEntry;
int i;
CDVDFS_init();
// check if the file exists
if (CDVD_findfile("SYSTEM.CNF;1", &tocEntry) != TRUE){
SysPrintf("SYSTEM.CNF not found\n");
return 0;//could not find; not a PS/PS2 cdvd
}
f=CDVDFS_open("SYSTEM.CNF;1", 1);
CDVDFS_read(f, buffer, 256);
CDVDFS_close(f);
buffer[tocEntry.fileSize]='\0';
// SysPrintf(
// "---------------------SYSTEM.CNF---------------------\n"
// "%s"
// "----------------------------------------------------\n", buffer);
pos=strstr(buffer, "BOOT2");
if (pos==NULL){
pos=strstr(buffer, "BOOT");
if (pos==NULL) {
SysPrintf("This is not a PS2 game!\n");
return 0;
}
return 1;
}
pos+=strlen("BOOT2");
while (pos && *pos && pos<=&buffer[255]
&& (*pos<'A' || (*pos>'Z' && *pos<'a') || *pos>'z'))
pos++;
if (!pos || *pos==0)
return 0;
sscanf(pos, "%s", name);
//SysPrintf("ELF name: '%s'\n", name);
if (strncmp("cdrom0:\\", name, 8) == 0) {
strncpy(CdromId, name+8, 11); CdromId[11] = 0;
}
// inifile_read(CdromId);
fp = fopen("System.map", "r");
if (fp) {
u32 addr;
SysPrintf("Loading System.map\n", fp);
while (!feof(fp)) {
fseek(fp, 8, SEEK_CUR);
buffer[0] = '0'; buffer[1] = 'x';
for (i=2; i<10; i++) buffer[i] = fgetc(fp); buffer[i] = 0;
addr = strtoul(buffer, (char**)NULL, 0);
fseek(fp, 3, SEEK_CUR);
for (i=0; i<256; i++) {
buffer[i] = fgetc(fp);
if (buffer[i] == '\n' || buffer[i] == 0) break;
}
if (buffer[i] == 0) break;
buffer[i] = 0;
disR5900AddSym(addr, buffer);
}
fclose(fp);
}
return 2;
}
/*#define PSX_EXE 1
#define CPE_EXE 2
#define COFF_EXE 3
#define INVALID_EXE 4
static int PSXGetFileType(FILE *f) {
unsigned long current;
unsigned long mybuf[2048];
EXE_HEADER *exe_hdr;
FILHDR *coff_hdr;
current = ftell(f);
fseek(f,0L,SEEK_SET);
fread(mybuf,2048,1,f);
fseek(f,current,SEEK_SET);
exe_hdr = (EXE_HEADER *)mybuf;
if (memcmp(exe_hdr->id,"PS-X EXE",8)==0)
return PSX_EXE;
if (mybuf[0]=='C' && mybuf[1]=='P' && mybuf[2]=='E')
return CPE_EXE;
coff_hdr = (FILHDR *)mybuf;
if (coff_hdr->f_magic == 0x0162)
return COFF_EXE;
return INVALID_EXE;
}
int Load(char *ExePath) {
FILE *tmpFile;
EXE_HEADER tmpHead;
int type;
strcpy(CdromId, "SLUS_999.99");
tmpFile = fopen(ExePath,"rb");
if (tmpFile == NULL) { SysMessage("Error opening file: %s", ExePath); return 0; }
type = PSXGetFileType(tmpFile);
switch (type) {
case PSX_EXE:
fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
fseek(tmpFile, 0x800, SEEK_SET);
fread((void *)PSXM(tmpHead.t_addr), tmpHead.t_size,1,tmpFile);
fclose(tmpFile);
psxRegs.pc = tmpHead.pc0;
psxRegs.GPR.n.gp = tmpHead.gp0;
psxRegs.GPR.n.sp = tmpHead.s_addr;
if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
break;
case CPE_EXE:
SysMessage("Pcsx found that you wanna use a CPE file. CPE files not support yet");
break;
case COFF_EXE:
SysMessage("Pcsx found that you wanna use a COFF file.COFF files not support yet");
break;
case INVALID_EXE:
SysMessage("This file is not a psx file");
break;
}
return 1;
}
*/
u16 logProtocol;
u8 logSource;
int connected=0;
#define SYNC_LOGGING
void __Log(char *fmt, ...) {
#ifdef EMU_LOG
va_list list;
static char tmp[2024]; //hm, should be enough
va_start(list, fmt);
#ifdef __WIN32__
if (connected && logProtocol>=0 && logProtocol<0x10){
vsprintf(tmp, fmt, list);
sendTTYP(logProtocol, logSource, tmp);
}//else //!!!!! is disabled, so the text goes to ttyp AND log
#endif
{
#ifndef LOG_STDOUT
if (varLog & 0x80000000) {
vsprintf(tmp, fmt, list);
SysPrintf(tmp);
} else if( emuLog != NULL ) {
vfprintf(emuLog, fmt, list);
}
#else //i assume that this will not be used (Florin)
vsprintf(tmp, fmt, list);
SysPrintf(tmp);
#endif
}
va_end(list);
#endif
}
// STATES
#define STATE_VERSION "STv6"
const char Pcsx2Header[32] = STATE_VERSION " PCSX2 v" PCSX2_VERSION;
#define _PS2Esave(type) \
if (type##freeze(FREEZE_SIZE, &fP) == -1) { \
gzclose(f); \
return -1; \
} \
fP.data = malloc(fP.size); \
if (fP.data == NULL) return -1; \
\
if (type##freeze(FREEZE_SAVE, &fP) == -1) { \
gzclose(f); \
return -1; \
} \
\
gzwrite(f, &fP.size, sizeof(fP.size)); \
if (fP.size) { \
gzwrite(f, fP.data, fP.size); \
free(fP.data); \
}
#define _PS2Eload(type) \
gzread(f, &fP.size, sizeof(fP.size)); \
if (fP.size) { \
fP.data = (s8*)malloc(fP.size); \
if (fP.data == NULL) return -1; \
gzread(f, fP.data, fP.size); \
} \
if (type##freeze(FREEZE_LOAD, &fP) == -1) { \
if (fP.size) free(fP.data); \
gzclose(f); \
return -1; \
} \
if (fP.size) free(fP.data);
extern void gsWaitGS();
extern u32 g_nextBranchCycle, g_psxNextBranchCycle;
int SaveState(char *file) {
gzFile f;
freezeData fP;
gsWaitGS();
SysPrintf("SaveState: %s\n", file);
f = gzopen(file, "wb");
if (f == NULL) return -1;
gzwrite(f, &dwSaveVersion, 4);
gzwrite(f, PS2MEM_BASE, 0x02000000); // 32 MB main memory
gzwrite(f, PS2MEM_ROM, 0x00400000); // 4 mb rom memory
gzwrite(f, PS2MEM_ROM1,0x00040000); // 256kb rom1 memory
gzwrite(f, PS2MEM_SCRATCH, 0x00004000); // scratch pad
gzwrite(f, PS2MEM_HW, 0x00010000); // hardware memory
gzwrite(f, (void*)&cpuRegs, sizeof(cpuRegs)); // cpu regs + COP0
gzwrite(f, (void*)&psxRegs, sizeof(psxRegs)); // iop regs]
gzwrite(f, (void*)&fpuRegs, sizeof(fpuRegs)); // fpu regs
gzwrite(f, (void*)&tlb, sizeof(tlb)); // tlbs
gzwrite(f, &EEsCycle, sizeof(EEsCycle));
gzwrite(f, &EEoCycle, sizeof(EEoCycle));
gzwrite(f, &IOPoCycle, sizeof(IOPoCycle));
gzwrite(f, &g_nextBranchCycle, sizeof(g_nextBranchCycle));
gzwrite(f, &g_psxNextBranchCycle, sizeof(g_psxNextBranchCycle));
gzwrite(f, &s_iLastCOP0Cycle, sizeof(s_iLastCOP0Cycle));
gzwrite(f, &g_psxWriteOk, sizeof(g_psxWriteOk));
//gzwrite(f, (void*)&ipuRegs, sizeof(IPUregisters)); // ipu regs
//hope didn't forgot any cpu....
rcntFreeze(f, 1);
gsFreeze(f, 1);
vu0Freeze(f, 1);
vu1Freeze(f, 1);
vif0Freeze(f, 1);
vif1Freeze(f, 1);
sifFreeze(f, 1);
ipuFreeze(f, 1);
// iop now
gzwrite(f, psxM, 0x00200000); // 2 MB main memory
//gzwrite(f, psxP, 0x00010000); // pralell memory
gzwrite(f, psxH, 0x00010000); // hardware memory
//gzwrite(f, psxS, 0x00010000); // sif memory
sioFreeze(f, 1);
cdrFreeze(f, 1);
cdvdFreeze(f, 1);
psxRcntFreeze(f, 1);
//mdecFreeze(f, 1);
sio2Freeze(f, 1);
SysPrintf("Saving GS\n");
_PS2Esave(GS);
SysPrintf("Saving SPU2\n");
_PS2Esave(SPU2);
SysPrintf("Saving DEV9\n");
_PS2Esave(DEV9);
SysPrintf("Saving USB\n");
_PS2Esave(USB);
SysPrintf("Saving ok\n");
gzclose(f);
return 0;
}
extern u32 dumplog;
extern u32 s_vucount;
int LoadState(char *file) {
gzFile f;
freezeData fP;
int i;
DWORD OldProtect;
DWORD dwVer;
#ifdef _DEBUG
s_vucount = 0;
//dumplog |= 2;
#endif
SysPrintf("LoadState: %s\n", file);
f = gzopen(file, "rb");
if (f == NULL) return -1;
gzread(f, &dwVer, 4);
if( dwVer != dwSaveVersion ) {
gzclose(f);
MessageBox(NULL, "Save state wrong version", "Error", MB_OK);
return 0;
}
// stop and reset the system first
gsWaitGS();
for (i=0; i<48; i++) ClearTLB(i);
Cpu->Reset();
recResetVU0();
recResetVU1();
psxCpu->Reset();
SysPrintf("Loading memory\n");
#ifdef WIN32_VIRTUAL_MEM
// make sure can write
VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READWRITE, &OldProtect);
VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READWRITE, &OldProtect);
VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READWRITE, &OldProtect);
VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READWRITE, &OldProtect);
#endif
gzread(f, PS2MEM_BASE, 0x02000000); // 32 MB main memory
gzread(f, PS2MEM_ROM, 0x00400000); // 4 mb rom memory
gzread(f, PS2MEM_ROM1,0x00040000); // 256kb rom1 memory
gzread(f, PS2MEM_SCRATCH, 0x00004000); // scratch pad
#ifdef WIN32_VIRTUAL_MEM
VirtualProtect(PS2MEM_ROM, 0x00400000, PAGE_READONLY, &OldProtect);
VirtualProtect(PS2MEM_ROM1, 0x00040000, PAGE_READONLY, &OldProtect);
VirtualProtect(PS2MEM_ROM2, 0x00080000, PAGE_READONLY, &OldProtect);
VirtualProtect(PS2MEM_EROM, 0x001C0000, PAGE_READONLY, &OldProtect);
#endif
gzread(f, PS2MEM_HW, 0x00010000); // hardware memory
SysPrintf("Loading structs\n");
gzread(f, (void*)&cpuRegs, sizeof(cpuRegs)); // cpu regs + COP0
gzread(f, (void*)&psxRegs, sizeof(psxRegs)); // iop regs
gzread(f, (void*)&fpuRegs, sizeof(fpuRegs)); // fpu regs
gzread(f, (void*)&tlb, sizeof(tlb)); // tlbs
gzread(f, &EEsCycle, sizeof(EEsCycle));
gzread(f, &EEoCycle, sizeof(EEoCycle));
gzread(f, &IOPoCycle, sizeof(IOPoCycle));
gzread(f, &g_nextBranchCycle, sizeof(g_nextBranchCycle));
gzread(f, &g_psxNextBranchCycle, sizeof(g_psxNextBranchCycle));
gzread(f, &s_iLastCOP0Cycle, sizeof(s_iLastCOP0Cycle));
gzread(f, &g_psxWriteOk, sizeof(g_psxWriteOk));
rcntFreeze(f, 0);
gsFreeze(f, 0);
vu0Freeze(f, 0);
vu1Freeze(f, 0);
vif0Freeze(f, 0);
vif1Freeze(f, 0);
sifFreeze(f, 0);
ipuFreeze(f, 0);
// iop now
SysPrintf("Loading iop mem\n");
gzread(f, psxM, 0x00200000); // 2 MB main memory
//gzread(f, psxP, 0x00010000); // pralell memory
gzread(f, psxH, 0x00010000); // hardware memory
//gzread(f, psxS, 0x00010000); // sif memory
SysPrintf("Loading iop stuff\n");
sioFreeze(f, 0);
cdrFreeze(f, 0);
cdvdFreeze(f, 0);
psxRcntFreeze(f, 0);
//mdecFreeze(f, 0);
sio2Freeze(f, 0);
SysPrintf("Loading GS\n");
_PS2Eload(GS);
SysPrintf("Loading SPU2\n");
_PS2Eload(SPU2);
SysPrintf("Loading DEV9\n");
_PS2Eload(DEV9);
SysPrintf("Loading USB\n");
_PS2Eload(USB);
SysPrintf("Loading ok\n");
gzclose(f);
//dumplog |= 4;
WriteCP0Status(cpuRegs.CP0.n.Status.val);
for (i=0; i<48; i++) WriteTLB(i);
return 0;
}
int CheckState(char *file) {
gzFile f;
char header[32];
f = gzopen(file, "rb");
if (f == NULL) return -1;
gzread(f, header, 32);
gzclose(f);
if (strncmp(STATE_VERSION " PCSX2", header, 10)) return -1;
return 0;
}
typedef struct {
char id[8];
char name[64];
} LangDef;
LangDef sLangs[] = {
{ "ar_AR", N_("Arabic") },
{ "bg_BG", N_("Bulgarian") },
{ "ca_CA", N_("Catalan") },
{ "du_DU", N_("Dutch") },
{ "de_DE", N_("German") },
{ "el_EL", N_("Greek") },
{ "en_US", N_("English") },
{ "fr_FR", N_("French") },
{ "hb_HB" , N_("Hebrew") },
{ "hu_HU", N_("Hungarian") },
{ "it_IT", N_("Italian") },
{ "ja_JA", N_("Japanese") },
{ "po_PO", N_("Portuguese") },
{ "pl_PL" , N_("Polish") },
{ "ro_RO", N_("Romanian") },
{ "ru_RU", N_("Russian") },
{ "es_ES", N_("Spanish") },
{ "sh_SH" , N_("S-Chinese") },
{ "tc_TC", N_("T-Chinese") },
{ "tr_TR", N_("Turkish") },
{ "", "" },
};
char *ParseLang(char *id) {
int i=0;
while (sLangs[i].id[0] != 0) {
if (!strcmp(id, sLangs[i].id))
return _(sLangs[i].name);
i++;
}
return id;
}
void injectIRX(char *filename){
struct stat buf;
char path[260], name[260], *p, *q;
struct romdir *rd;
int iROMDIR=-1, iIOPBTCONF=-1, iBLANK=-1, i, filesize;
FILE *fp;
strcpy(name, filename);
for (i=0; name[i] && name[i]!='.' && i<10; i++) name[i]=toupper(name[i]);name[i]=0;
//phase 1: find ROMDIR in bios
for (p=PS2MEM_ROM; p<PS2MEM_ROM+0x80000; p++)
if (strncmp(p, "RESET", 5)==0)
break;
rd=(struct romdir*)p;
for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, name, strlen(name))==0)break;
if (rd[i].fileName[0])return;//already in;)
//phase 2: make room in IOPBTCONF & ROMDIR
for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "ROMDIR", 6)==0)iROMDIR=i;
for (i=0; rd[i].fileName[0]; i++)if (strncmp(rd[i].fileName, "IOPBTCONF", 9)==0)iIOPBTCONF=i;
for (i=0; rd[i].fileName[0]; i++)if (rd[i].fileName[0]=='-')break; iBLANK=i;
rd[iBLANK].fileSize-=DIRENTRY_SIZE+DIRENTRY_SIZE;
p=PS2MEM_ROM;for (i=0; i<iBLANK; i++)p+=(rd[i].fileSize+0xF)&(~0xF);p+=DIRENTRY_SIZE;
q=PS2MEM_ROM;for (i=0; i<=iIOPBTCONF; i++) q+=(rd[i].fileSize+0xF)&(~0xF);
while (p-16>q){*((u64*)p)=*((u64*)p-4);*((u64*)p+1)=*((u64*)p-3);p-=DIRENTRY_SIZE;}
*((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iIOPBTCONF].fileSize+=DIRENTRY_SIZE;
q=PS2MEM_ROM;for (i=0; i<=iROMDIR; i++) q+=(rd[i].fileSize+0xF)&(~0xF);
while (p >q){*((u64*)p)=*((u64*)p-2);*((u64*)p+1)=*((u64*)p-1);p-=DIRENTRY_SIZE;}
*((u64*)p)=*((u64*)p+1)=0;p-=DIRENTRY_SIZE;rd[iROMDIR].fileSize+=DIRENTRY_SIZE;
//phase 3: add the name to the end of IOPBTCONF
p=PS2MEM_ROM;for (i=0; i<iIOPBTCONF; i++) p+=(rd[i].fileSize+0xF)&(~0xF);while(*p) p++;//go to end of file
strcpy(p, name);p[strlen(name)]=0xA;
//phase 4: find file
strcpy(path, Config.BiosDir);
strcat(path, filename);
if (stat(path, &buf) == -1){
SysMessage(_("Unable to hack in %s%s\n"), Config.BiosDir, filename);
return;
}
//phase 5: add the file to the end of the bios
p=PS2MEM_ROM;for (i=0; rd[i].fileName[0]; i++)p+=(rd[i].fileSize+0xF)&(~0xF);
fp=fopen(path, "rb");
fseek(fp, 0, SEEK_END);
filesize=ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(p, 1, filesize, fp);
fclose(fp);
//phase 6: register it in ROMDIR
memset(rd[i].fileName, 0, 10);
memcpy(rd[i].fileName, name, strlen(name));
rd[i].fileSize=filesize;
rd[i].extInfoSize=0;
}