Fix detection of some CDs such as Wild Arms USA detected as a PAL game. (#222)
[pcsx_rearmed.git] / libpcsxcore / misc.c
... / ...
CommitLineData
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"
27#include "gpu.h"
28#include "ppf.h"
29#include "database.h"
30#include <zlib.h>
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;
60#if defined(__arm__)
61 unsigned char *u = (void *)b;
62 int block = (u[3] << 24) | (u[2] << 16) | (u[1] << 8) | u[0];
63#elif defined(__BIGENDIAN__)
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; \
99 buf = (void *)CDR_getBuffer(); \
100 if (buf == NULL) return -1; \
101 else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
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
111int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
112 struct iso_directory_record *dir;
113 int retval = -1;
114 u8 ddir[4096];
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 }
127 i += (u8)dir->length[0];
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);
143 retval = 0;
144 break;
145 }
146 }
147 }
148 return retval;
149}
150
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
173int LoadCdrom() {
174 EXE_HEADER tmpHead;
175 struct iso_directory_record *dir;
176 u8 time[4], *buf;
177 u8 mdir[4096];
178 char exename[256];
179
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
184 if (!Config.HLE) {
185 // skip BIOS logos
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
212 sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
213 if (GetCdromFile(mdir, time, exename) == -1) {
214 sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
215 if (GetCdromFile(mdir, time, exename) == -1) {
216 char *ptr = strstr((char *)buf + 12, "cdrom:");
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
246 psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
247
248 // Read the rest of the main executable
249 while (tmpHead.t_size & ~2047) {
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;
267 u8 mdir[4096];
268 char exename[256];
269 u32 size, addr;
270 void *mem;
271
272 sscanf(filename, "cdrom:\\%255s", exename);
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
293 psxCpu->Clear(addr, size / 4);
294
295 while (size & ~2047) {
296 incTime();
297 READTRACK();
298
299 mem = PSXM(addr);
300 if (mem)
301 memcpy(mem, buf + 12, 2048);
302
303 size -= 2048;
304 addr += 2048;
305 }
306
307 return 0;
308}
309
310int CheckCdrom() {
311 struct iso_directory_record *dir;
312 unsigned char time[4];
313 char *buf;
314 unsigned char mdir[4096];
315 char exename[256];
316 int i, len, c;
317
318 FreePPFCache();
319
320 time[0] = itob(0);
321 time[1] = itob(2);
322 time[2] = itob(0x10);
323
324 READTRACK();
325
326 memset(CdromLabel, 0, sizeof(CdromLabel));
327 memset(CdromId, 0, sizeof(CdromId));
328 memset(exename, 0, sizeof(exename));
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
342 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
343 if (GetCdromFile(mdir, time, exename) == -1) {
344 sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
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') {
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];
375 }
376 }
377
378 if (CdromId[0] == '\0')
379 strcpy(CdromId, "SLUS99999");
380
381 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
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.
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);
398 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
399
400 Apply_Hacks_Cdrom();
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
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
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;
455 void *mem;
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);
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);
474 fread_to_ram(mem, section_size, 1, tmpFile);
475 psxCpu->Clear(section_address, section_size / 4);
476 }
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
498 mem = PSXM(section_address);
499 if (mem != NULL) {
500 fread_to_ram(mem, section_size, 1, tmpFile);
501 psxCpu->Clear(section_address, section_size / 4);
502 }
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:
523 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
524 SysPrintf(_("(did you forget -cdfile ?)\n"));
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
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
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.
573static const u32 SaveVersion = 0x8b410006;
574
575int SaveState(const char *file) {
576 void *f;
577 GPUFreeze_t *gpufP;
578 SPUFreeze_t *spufP;
579 int Size;
580 unsigned char *pMem;
581
582 f = SaveFuncs.open(file, "wb");
583 if (f == NULL) return -1;
584
585 new_dyna_before_save();
586
587 SaveFuncs.write(f, (void *)PcsxHeader, 32);
588 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
589 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
590
591 pMem = (unsigned char *)malloc(128 * 96 * 3);
592 if (pMem == NULL) return -1;
593 GPU_getScreenPic(pMem);
594 SaveFuncs.write(f, pMem, 128 * 96 * 3);
595 free(pMem);
596
597 if (Config.HLE)
598 psxBiosFreeze(1);
599
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));
604
605 // gpu
606 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
607 gpufP->ulFreezeVersion = 1;
608 GPU_freeze(1, gpufP);
609 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
610 free(gpufP);
611
612 // spu
613 spufP = (SPUFreeze_t *) malloc(16);
614 SPU_freeze(2, spufP, psxRegs.cycle);
615 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
616 free(spufP);
617 spufP = (SPUFreeze_t *) malloc(Size);
618 SPU_freeze(1, spufP, psxRegs.cycle);
619 SaveFuncs.write(f, spufP, Size);
620 free(spufP);
621
622 sioFreeze(f, 1);
623 cdrFreeze(f, 1);
624 psxHwFreeze(f, 1);
625 psxRcntFreeze(f, 1);
626 mdecFreeze(f, 1);
627 new_dyna_freeze(f, 1);
628
629 SaveFuncs.close(f);
630
631 new_dyna_after_save();
632
633 return 0;
634}
635
636int LoadState(const char *file) {
637 void *f;
638 GPUFreeze_t *gpufP;
639 SPUFreeze_t *spufP;
640 int Size;
641 char header[32];
642 u32 version;
643 boolean hle;
644
645 f = SaveFuncs.open(file, "rb");
646 if (f == NULL) return -1;
647
648 SaveFuncs.read(f, header, sizeof(header));
649 SaveFuncs.read(f, &version, sizeof(u32));
650 SaveFuncs.read(f, &hle, sizeof(boolean));
651
652 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
653 SaveFuncs.close(f);
654 return -1;
655 }
656 Config.HLE = hle;
657
658 if (Config.HLE)
659 psxBiosInit();
660
661 psxCpu->Reset();
662 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
663
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));
668
669 if (Config.HLE)
670 psxBiosFreeze(0);
671
672 // gpu
673 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
674 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
675 GPU_freeze(0, gpufP);
676 free(gpufP);
677 if (HW_GPU_STATUS == 0)
678 HW_GPU_STATUS = GPU_readStatus();
679
680 // spu
681 SaveFuncs.read(f, &Size, 4);
682 spufP = (SPUFreeze_t *)malloc(Size);
683 SaveFuncs.read(f, spufP, Size);
684 SPU_freeze(0, spufP, psxRegs.cycle);
685 free(spufP);
686
687 sioFreeze(f, 0);
688 cdrFreeze(f, 0);
689 psxHwFreeze(f, 0);
690 psxRcntFreeze(f, 0);
691 mdecFreeze(f, 0);
692 new_dyna_freeze(f, 0);
693
694 SaveFuncs.close(f);
695
696 return 0;
697}
698
699int CheckState(const char *file) {
700 void *f;
701 char header[32];
702 u32 version;
703 boolean hle;
704
705 f = SaveFuncs.open(file, "rb");
706 if (f == NULL) return -1;
707
708 SaveFuncs.read(f, header, sizeof(header));
709 SaveFuncs.read(f, &version, sizeof(u32));
710 SaveFuncs.read(f, &hle, sizeof(boolean));
711
712 SaveFuncs.close(f);
713
714 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
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();
754#ifndef DRC_DISABLE
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}