Fix detection of some CDs such as Wild Arms USA detected as a PAL game. (#222)
[pcsx_rearmed.git] / libpcsxcore / misc.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
18 ***************************************************************************/
19
20/*
21* Miscellaneous functions, including savestates and CD-ROM loading.
22*/
23
24#include "misc.h"
25#include "cdrom.h"
26#include "mdec.h"
ddbaf678 27#include "gpu.h"
ef79bbde 28#include "ppf.h"
eedfe806 29#include "database.h"
496d88d4 30#include <zlib.h>
ef79bbde
P
31
32char CdromId[10] = "";
33char CdromLabel[33] = "";
34
35// PSX Executable types
36#define PSX_EXE 1
37#define CPE_EXE 2
38#define COFF_EXE 3
39#define INVALID_EXE 4
40
41#define ISODCL(from, to) (to - from + 1)
42
43struct iso_directory_record {
44 char length [ISODCL (1, 1)]; /* 711 */
45 char ext_attr_length [ISODCL (2, 2)]; /* 711 */
46 char extent [ISODCL (3, 10)]; /* 733 */
47 char size [ISODCL (11, 18)]; /* 733 */
48 char date [ISODCL (19, 25)]; /* 7 by 711 */
49 char flags [ISODCL (26, 26)];
50 char file_unit_size [ISODCL (27, 27)]; /* 711 */
51 char interleave [ISODCL (28, 28)]; /* 711 */
52 char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
53 unsigned char name_len [ISODCL (33, 33)]; /* 711 */
54 char name [1];
55};
56
57void mmssdd( char *b, char *p )
58{
59 int m, s, d;
507aaf98 60#if defined(__arm__)
7e443736 61 unsigned char *u = (void *)b;
62 int block = (u[3] << 24) | (u[2] << 16) | (u[1] << 8) | u[0];
507aaf98 63#elif defined(__BIGENDIAN__)
ef79bbde
P
64 int block = (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | (b[3] << 24);
65#else
66 int block = *((int*)b);
67#endif
68
69 block += 150;
70 m = block / 4500; // minutes
71 block = block - m * 4500; // minutes rest
72 s = block / 75; // seconds
73 d = block - s * 75; // seconds rest
74
75 m = ((m / 10) << 4) | m % 10;
76 s = ((s / 10) << 4) | s % 10;
77 d = ((d / 10) << 4) | d % 10;
78
79 p[0] = m;
80 p[1] = s;
81 p[2] = d;
82}
83
84#define incTime() \
85 time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \
86 time[2]++; \
87 if(time[2] == 75) { \
88 time[2] = 0; \
89 time[1]++; \
90 if (time[1] == 60) { \
91 time[1] = 0; \
92 time[0]++; \
93 } \
94 } \
95 time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]);
96
97#define READTRACK() \
98 if (CDR_readTrack(time) == -1) return -1; \
305c8c93 99 buf = (void *)CDR_getBuffer(); \
100 if (buf == NULL) return -1; \
101 else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
ef79bbde
P
102
103#define READDIR(_dir) \
104 READTRACK(); \
105 memcpy(_dir, buf + 12, 2048); \
106 \
107 incTime(); \
108 READTRACK(); \
109 memcpy(_dir + 2048, buf + 12, 2048);
110
305c8c93 111int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
ef79bbde 112 struct iso_directory_record *dir;
5be6eaeb 113 int retval = -1;
305c8c93 114 u8 ddir[4096];
ef79bbde
P
115 u8 *buf;
116 int i;
117
118 // only try to scan if a filename is given
119 if (!strlen(filename)) return -1;
120
121 i = 0;
122 while (i < 4096) {
123 dir = (struct iso_directory_record*) &mdir[i];
124 if (dir->length[0] == 0) {
125 return -1;
126 }
1c2c2bfb 127 i += (u8)dir->length[0];
ef79bbde
P
128
129 if (dir->flags[0] & 0x2) { // it's a dir
130 if (!strnicmp((char *)&dir->name[0], filename, dir->name_len[0])) {
131 if (filename[dir->name_len[0]] != '\\') continue;
132
133 filename += dir->name_len[0] + 1;
134
135 mmssdd(dir->extent, (char *)time);
136 READDIR(ddir);
137 i = 0;
138 mdir = ddir;
139 }
140 } else {
141 if (!strnicmp((char *)&dir->name[0], filename, strlen(filename))) {
142 mmssdd(dir->extent, (char *)time);
5be6eaeb 143 retval = 0;
ef79bbde
P
144 break;
145 }
146 }
147 }
5be6eaeb 148 return retval;
ef79bbde
P
149}
150
f3a78e7e 151static const unsigned int gpu_ctl_def[] = {
152 0x00000000, 0x01000000, 0x03000000, 0x04000000,
153 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
154};
155
156static const unsigned int gpu_data_def[] = {
157 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
158 0xe5001000, 0xe6000000,
159 0x02000000, 0x00000000, 0x01ff03ff,
160};
161
162static void fake_bios_gpu_setup(void)
163{
164 int i;
165
166 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
167 GPU_writeStatus(gpu_ctl_def[i]);
168
169 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
170 GPU_writeData(gpu_data_def[i]);
171}
172
ef79bbde
P
173int LoadCdrom() {
174 EXE_HEADER tmpHead;
175 struct iso_directory_record *dir;
176 u8 time[4], *buf;
177 u8 mdir[4096];
305c8c93 178 char exename[256];
ef79bbde 179
f3a78e7e 180 // not the best place to do it, but since BIOS boot logo killer
181 // is just below, do it here
182 fake_bios_gpu_setup();
183
ef79bbde 184 if (!Config.HLE) {
f3a78e7e 185 // skip BIOS logos
ef79bbde
P
186 psxRegs.pc = psxRegs.GPR.n.ra;
187 return 0;
188 }
189
190 time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
191
192 READTRACK();
193
194 // skip head and sub, and go to the root directory record
195 dir = (struct iso_directory_record*) &buf[12+156];
196
197 mmssdd(dir->extent, (char*)time);
198
199 READDIR(mdir);
200
201 // Load SYSTEM.CNF and scan for the main executable
202 if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) {
203 // if SYSTEM.CNF is missing, start an existing PSX.EXE
204 if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1;
205
206 READTRACK();
207 }
208 else {
209 // read the SYSTEM.CNF
210 READTRACK();
211
9a9bcd78 212 sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 213 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 214 sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde 215 if (GetCdromFile(mdir, time, exename) == -1) {
305c8c93 216 char *ptr = strstr((char *)buf + 12, "cdrom:");
ef79bbde
P
217 if (ptr != NULL) {
218 ptr += 6;
219 while (*ptr == '\\' || *ptr == '/') ptr++;
220 strncpy(exename, ptr, 255);
221 exename[255] = '\0';
222 ptr = exename;
223 while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
224 *ptr = '\0';
225 if (GetCdromFile(mdir, time, exename) == -1)
226 return -1;
227 } else
228 return -1;
229 }
230 }
231
232 // Read the EXE-Header
233 READTRACK();
234 }
235
236 memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
237
238 psxRegs.pc = SWAP32(tmpHead.pc0);
239 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
240 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
241 if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
242
243 tmpHead.t_size = SWAP32(tmpHead.t_size);
244 tmpHead.t_addr = SWAP32(tmpHead.t_addr);
245
ebe6ff2b 246 psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
247
ef79bbde 248 // Read the rest of the main executable
ebe6ff2b 249 while (tmpHead.t_size & ~2047) {
ef79bbde
P
250 void *ptr = (void *)PSXM(tmpHead.t_addr);
251
252 incTime();
253 READTRACK();
254
255 if (ptr != NULL) memcpy(ptr, buf+12, 2048);
256
257 tmpHead.t_size -= 2048;
258 tmpHead.t_addr += 2048;
259 }
260
261 return 0;
262}
263
264int LoadCdromFile(const char *filename, EXE_HEADER *head) {
265 struct iso_directory_record *dir;
266 u8 time[4],*buf;
305c8c93 267 u8 mdir[4096];
268 char exename[256];
ef79bbde 269 u32 size, addr;
305c8c93 270 void *mem;
ef79bbde 271
9a9bcd78 272 sscanf(filename, "cdrom:\\%255s", exename);
ef79bbde
P
273
274 time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
275
276 READTRACK();
277
278 // skip head and sub, and go to the root directory record
279 dir = (struct iso_directory_record *)&buf[12 + 156];
280
281 mmssdd(dir->extent, (char*)time);
282
283 READDIR(mdir);
284
285 if (GetCdromFile(mdir, time, exename) == -1) return -1;
286
287 READTRACK();
288
289 memcpy(head, buf + 12, sizeof(EXE_HEADER));
290 size = head->t_size;
291 addr = head->t_addr;
292
ebe6ff2b 293 psxCpu->Clear(addr, size / 4);
294
295 while (size & ~2047) {
ef79bbde
P
296 incTime();
297 READTRACK();
298
305c8c93 299 mem = PSXM(addr);
300 if (mem)
301 memcpy(mem, buf + 12, 2048);
ef79bbde
P
302
303 size -= 2048;
304 addr += 2048;
305 }
306
307 return 0;
308}
309
310int CheckCdrom() {
311 struct iso_directory_record *dir;
305c8c93 312 unsigned char time[4];
313 char *buf;
ef79bbde
P
314 unsigned char mdir[4096];
315 char exename[256];
e06ee7f4 316 int i, len, c;
ef79bbde
P
317
318 FreePPFCache();
319
320 time[0] = itob(0);
321 time[1] = itob(2);
322 time[2] = itob(0x10);
323
324 READTRACK();
325
e06ee7f4 326 memset(CdromLabel, 0, sizeof(CdromLabel));
327 memset(CdromId, 0, sizeof(CdromId));
328 memset(exename, 0, sizeof(exename));
ef79bbde
P
329
330 strncpy(CdromLabel, buf + 52, 32);
331
332 // skip head and sub, and go to the root directory record
333 dir = (struct iso_directory_record *)&buf[12 + 156];
334
335 mmssdd(dir->extent, (char *)time);
336
337 READDIR(mdir);
338
339 if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
340 READTRACK();
341
9a9bcd78 342 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 343 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 344 sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde
P
345 if (GetCdromFile(mdir, time, exename) == -1) {
346 char *ptr = strstr(buf + 12, "cdrom:"); // possibly the executable is in some subdir
347 if (ptr != NULL) {
348 ptr += 6;
349 while (*ptr == '\\' || *ptr == '/') ptr++;
350 strncpy(exename, ptr, 255);
351 exename[255] = '\0';
352 ptr = exename;
353 while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
354 *ptr = '\0';
355 if (GetCdromFile(mdir, time, exename) == -1)
356 return -1; // main executable not found
357 } else
358 return -1;
359 }
360 }
361 } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
362 strcpy(exename, "PSX.EXE;1");
363 strcpy(CdromId, "SLUS99999");
364 } else
365 return -1; // SYSTEM.CNF and PSX.EXE not found
366
367 if (CdromId[0] == '\0') {
e06ee7f4 368 len = strlen(exename);
369 c = 0;
370 for (i = 0; i < len; ++i) {
371 if (exename[i] == ';' || c >= sizeof(CdromId) - 1)
372 break;
373 if (isalnum(exename[i]))
374 CdromId[c++] = exename[i];
ef79bbde
P
375 }
376 }
377
0e2e3f49 378 if (CdromId[0] == '\0')
379 strcpy(CdromId, "SLUS99999");
380
ef79bbde 381 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
40337130 382 if (
383 /* Make sure Wild Arms SCUS-94608 is not detected as a PAL game. */
384 ((CdromId[0] == 's' || CdromId[0] == 'S') && (CdromId[2] == 'e' || CdromId[2] == 'E')) ||
385 !strncmp(CdromId, "DTLS3035", 8) ||
386 !strncmp(CdromId, "PBPX95001", 9) || // according to redump.org, these PAL
387 !strncmp(CdromId, "PBPX95007", 9) || // discs have a non-standard ID;
388 !strncmp(CdromId, "PBPX95008", 9)) // add more serials if they are discovered.
ef79bbde
P
389 Config.PsxType = PSX_TYPE_PAL; // pal
390 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
391 }
392
393 if (CdromLabel[0] == ' ') {
394 strncpy(CdromLabel, CdromId, 9);
395 }
396 SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
397 SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
e06ee7f4 398 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
eedfe806 399
400 Apply_Hacks_Cdrom();
ef79bbde
P
401
402 BuildPPFCache();
403
404 return 0;
405}
406
407static int PSXGetFileType(FILE *f) {
408 unsigned long current;
409 u8 mybuf[2048];
410 EXE_HEADER *exe_hdr;
411 FILHDR *coff_hdr;
412
413 current = ftell(f);
414 fseek(f, 0L, SEEK_SET);
415 fread(mybuf, 2048, 1, f);
416 fseek(f, current, SEEK_SET);
417
418 exe_hdr = (EXE_HEADER *)mybuf;
419 if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
420 return PSX_EXE;
421
422 if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
423 return CPE_EXE;
424
425 coff_hdr = (FILHDR *)mybuf;
426 if (SWAPu16(coff_hdr->f_magic) == 0x0162)
427 return COFF_EXE;
428
429 return INVALID_EXE;
430}
431
96bef96f 432// temporary pandora workaround..
433// FIXME: remove
434size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
435{
436 void *tmp;
437 size_t ret = 0;
438
439 tmp = malloc(size * nmemb);
440 if (tmp) {
441 ret = fread(tmp, size, nmemb, stream);
442 memcpy(ptr, tmp, size * nmemb);
443 free(tmp);
444 }
445 return ret;
446}
447
ef79bbde
P
448int Load(const char *ExePath) {
449 FILE *tmpFile;
450 EXE_HEADER tmpHead;
451 int type;
452 int retval = 0;
453 u8 opcode;
454 u32 section_address, section_size;
ebe6ff2b 455 void *mem;
ef79bbde
P
456
457 strncpy(CdromId, "SLUS99999", 9);
458 strncpy(CdromLabel, "SLUS_999.99", 11);
459
460 tmpFile = fopen(ExePath, "rb");
461 if (tmpFile == NULL) {
462 SysPrintf(_("Error opening file: %s.\n"), ExePath);
463 retval = -1;
464 } else {
465 type = PSXGetFileType(tmpFile);
466 switch (type) {
467 case PSX_EXE:
468 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
ebe6ff2b 469 section_address = SWAP32(tmpHead.t_addr);
470 section_size = SWAP32(tmpHead.t_size);
471 mem = PSXM(section_address);
472 if (mem != NULL) {
473 fseek(tmpFile, 0x800, SEEK_SET);
96bef96f 474 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 475 psxCpu->Clear(section_address, section_size / 4);
476 }
ef79bbde
P
477 fclose(tmpFile);
478 psxRegs.pc = SWAP32(tmpHead.pc0);
479 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
480 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
481 if (psxRegs.GPR.n.sp == 0)
482 psxRegs.GPR.n.sp = 0x801fff00;
483 retval = 0;
484 break;
485 case CPE_EXE:
486 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
487 do {
488 fread(&opcode, 1, 1, tmpFile);
489 switch (opcode) {
490 case 1: /* Section loading */
491 fread(&section_address, 4, 1, tmpFile);
492 fread(&section_size, 4, 1, tmpFile);
493 section_address = SWAPu32(section_address);
494 section_size = SWAPu32(section_size);
495#ifdef EMU_LOG
496 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
497#endif
ebe6ff2b 498 mem = PSXM(section_address);
499 if (mem != NULL) {
96bef96f 500 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 501 psxCpu->Clear(section_address, section_size / 4);
502 }
ef79bbde
P
503 break;
504 case 3: /* register loading (PC only?) */
505 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
506 fread(&psxRegs.pc, 4, 1, tmpFile);
507 psxRegs.pc = SWAPu32(psxRegs.pc);
508 break;
509 case 0: /* End of file */
510 break;
511 default:
512 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
513 retval = -1;
514 break;
515 }
516 } while (opcode != 0 && retval == 0);
517 break;
518 case COFF_EXE:
519 SysPrintf(_("COFF files not supported.\n"));
520 retval = -1;
521 break;
522 case INVALID_EXE:
8f00f96c 523 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
524 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
525 retval = -1;
526 break;
527 }
528 }
529
530 if (retval != 0) {
531 CdromId[0] = '\0';
532 CdromLabel[0] = '\0';
533 }
534
535 return retval;
536}
537
538// STATES
539
496d88d4 540static void *zlib_open(const char *name, const char *mode)
541{
542 return gzopen(name, mode);
543}
544
545static int zlib_read(void *file, void *buf, u32 len)
546{
547 return gzread(file, buf, len);
548}
549
550static int zlib_write(void *file, const void *buf, u32 len)
551{
552 return gzwrite(file, buf, len);
553}
554
555static long zlib_seek(void *file, long offs, int whence)
556{
557 return gzseek(file, offs, whence);
558}
559
560static void zlib_close(void *file)
561{
562 gzclose(file);
563}
564
565struct PcsxSaveFuncs SaveFuncs = {
566 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
567};
568
ef79bbde
P
569static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
570
571// Savestate Versioning!
572// If you make changes to the savestate version, please increment the value below.
df656dde 573static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
574
575int SaveState(const char *file) {
496d88d4 576 void *f;
ef79bbde
P
577 GPUFreeze_t *gpufP;
578 SPUFreeze_t *spufP;
579 int Size;
580 unsigned char *pMem;
581
496d88d4 582 f = SaveFuncs.open(file, "wb");
ef79bbde
P
583 if (f == NULL) return -1;
584
03f55e6b 585 new_dyna_before_save();
52082bc1 586
496d88d4 587 SaveFuncs.write(f, (void *)PcsxHeader, 32);
588 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
589 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
590
591 pMem = (unsigned char *)malloc(128 * 96 * 3);
592 if (pMem == NULL) return -1;
593 GPU_getScreenPic(pMem);
496d88d4 594 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
595 free(pMem);
596
597 if (Config.HLE)
598 psxBiosFreeze(1);
599
496d88d4 600 SaveFuncs.write(f, psxM, 0x00200000);
601 SaveFuncs.write(f, psxR, 0x00080000);
602 SaveFuncs.write(f, psxH, 0x00010000);
603 SaveFuncs.write(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
604
605 // gpu
606 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
607 gpufP->ulFreezeVersion = 1;
608 GPU_freeze(1, gpufP);
496d88d4 609 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
610 free(gpufP);
611
612 // spu
613 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 614 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 615 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
616 free(spufP);
617 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 618 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 619 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
620 free(spufP);
621
622 sioFreeze(f, 1);
623 cdrFreeze(f, 1);
624 psxHwFreeze(f, 1);
625 psxRcntFreeze(f, 1);
626 mdecFreeze(f, 1);
03f55e6b 627 new_dyna_freeze(f, 1);
ef79bbde 628
496d88d4 629 SaveFuncs.close(f);
ef79bbde 630
5b8c000f 631 new_dyna_after_save();
632
ef79bbde
P
633 return 0;
634}
635
636int LoadState(const char *file) {
496d88d4 637 void *f;
ef79bbde
P
638 GPUFreeze_t *gpufP;
639 SPUFreeze_t *spufP;
640 int Size;
641 char header[32];
642 u32 version;
643 boolean hle;
644
496d88d4 645 f = SaveFuncs.open(file, "rb");
ef79bbde
P
646 if (f == NULL) return -1;
647
496d88d4 648 SaveFuncs.read(f, header, sizeof(header));
649 SaveFuncs.read(f, &version, sizeof(u32));
650 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 651
33f56da1 652 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 653 SaveFuncs.close(f);
ef79bbde
P
654 return -1;
655 }
33f56da1 656 Config.HLE = hle;
657
658 if (Config.HLE)
659 psxBiosInit();
ef79bbde
P
660
661 psxCpu->Reset();
496d88d4 662 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 663
496d88d4 664 SaveFuncs.read(f, psxM, 0x00200000);
665 SaveFuncs.read(f, psxR, 0x00080000);
666 SaveFuncs.read(f, psxH, 0x00010000);
667 SaveFuncs.read(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
668
669 if (Config.HLE)
670 psxBiosFreeze(0);
671
672 // gpu
673 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 674 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
675 GPU_freeze(0, gpufP);
676 free(gpufP);
ddbaf678 677 if (HW_GPU_STATUS == 0)
678 HW_GPU_STATUS = GPU_readStatus();
ef79bbde
P
679
680 // spu
496d88d4 681 SaveFuncs.read(f, &Size, 4);
ef79bbde 682 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 683 SaveFuncs.read(f, spufP, Size);
650adfd2 684 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
685 free(spufP);
686
687 sioFreeze(f, 0);
688 cdrFreeze(f, 0);
689 psxHwFreeze(f, 0);
690 psxRcntFreeze(f, 0);
691 mdecFreeze(f, 0);
03f55e6b 692 new_dyna_freeze(f, 0);
ef79bbde 693
496d88d4 694 SaveFuncs.close(f);
ef79bbde
P
695
696 return 0;
697}
698
699int CheckState(const char *file) {
496d88d4 700 void *f;
ef79bbde
P
701 char header[32];
702 u32 version;
703 boolean hle;
704
496d88d4 705 f = SaveFuncs.open(file, "rb");
ef79bbde
P
706 if (f == NULL) return -1;
707
496d88d4 708 SaveFuncs.read(f, header, sizeof(header));
709 SaveFuncs.read(f, &version, sizeof(u32));
710 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 711
496d88d4 712 SaveFuncs.close(f);
ef79bbde 713
33f56da1 714 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
715 return -1;
716
717 return 0;
718}
719
720// NET Function Helpers
721
722int SendPcsxInfo() {
723 if (NET_recvData == NULL || NET_sendData == NULL)
724 return 0;
725
726 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
727 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
728 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
729 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
730 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
731 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
732
733 return 0;
734}
735
736int RecvPcsxInfo() {
737 int tmp;
738
739 if (NET_recvData == NULL || NET_sendData == NULL)
740 return 0;
741
742 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
743 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
744 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
745 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
746 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
747
748 SysUpdate();
749
750 tmp = Config.Cpu;
751 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
752 if (tmp != Config.Cpu) {
753 psxCpu->Shutdown();
41e82ad4 754#ifndef DRC_DISABLE
ef79bbde
P
755 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
756 else psxCpu = &psxRec;
757#else
758 psxCpu = &psxInt;
759#endif
760 if (psxCpu->Init() == -1) {
761 SysClose(); return -1;
762 }
763 psxCpu->Reset();
764 }
765
766 return 0;
767}
768
769// remove the leading and trailing spaces in a string
770void trim(char *str) {
771 int pos = 0;
772 char *dest = str;
773
774 // skip leading blanks
775 while (str[pos] <= ' ' && str[pos] > 0)
776 pos++;
777
778 while (str[pos]) {
779 *(dest++) = str[pos];
780 pos++;
781 }
782
783 *(dest--) = '\0'; // store the null
784
785 // remove trailing blanks
786 while (dest >= str && *dest <= ' ' && *dest > 0)
787 *(dest--) = '\0';
788}
789
790// lookup table for crc calculation
791static unsigned short crctab[256] = {
792 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
793 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
794 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
795 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
796 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
797 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
798 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
799 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
800 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
801 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
802 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
803 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
804 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
805 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
806 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
807 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
808 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
809 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
810 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
811 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
812 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
813 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
814 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
815 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
816 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
817 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
818 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
819 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
820 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
821};
822
823u16 calcCrc(u8 *d, int len) {
824 u16 crc = 0;
825 int i;
826
827 for (i = 0; i < len; i++) {
828 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
829 }
830
831 return ~crc;
832}