Add internal database for problematic games. (#182)
[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 (CdromId[2] == 'e' || CdromId[2] == 'E')
383 Config.PsxType = PSX_TYPE_PAL; // pal
384 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
385 }
386
387 if (CdromLabel[0] == ' ') {
388 strncpy(CdromLabel, CdromId, 9);
389 }
390 SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
391 SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
392 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
393
394 Apply_Hacks_Cdrom();
395
396 BuildPPFCache();
397
398 return 0;
399}
400
401static int PSXGetFileType(FILE *f) {
402 unsigned long current;
403 u8 mybuf[2048];
404 EXE_HEADER *exe_hdr;
405 FILHDR *coff_hdr;
406
407 current = ftell(f);
408 fseek(f, 0L, SEEK_SET);
409 fread(mybuf, 2048, 1, f);
410 fseek(f, current, SEEK_SET);
411
412 exe_hdr = (EXE_HEADER *)mybuf;
413 if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
414 return PSX_EXE;
415
416 if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
417 return CPE_EXE;
418
419 coff_hdr = (FILHDR *)mybuf;
420 if (SWAPu16(coff_hdr->f_magic) == 0x0162)
421 return COFF_EXE;
422
423 return INVALID_EXE;
424}
425
426// temporary pandora workaround..
427// FIXME: remove
428size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
429{
430 void *tmp;
431 size_t ret = 0;
432
433 tmp = malloc(size * nmemb);
434 if (tmp) {
435 ret = fread(tmp, size, nmemb, stream);
436 memcpy(ptr, tmp, size * nmemb);
437 free(tmp);
438 }
439 return ret;
440}
441
442int Load(const char *ExePath) {
443 FILE *tmpFile;
444 EXE_HEADER tmpHead;
445 int type;
446 int retval = 0;
447 u8 opcode;
448 u32 section_address, section_size;
449 void *mem;
450
451 strncpy(CdromId, "SLUS99999", 9);
452 strncpy(CdromLabel, "SLUS_999.99", 11);
453
454 tmpFile = fopen(ExePath, "rb");
455 if (tmpFile == NULL) {
456 SysPrintf(_("Error opening file: %s.\n"), ExePath);
457 retval = -1;
458 } else {
459 type = PSXGetFileType(tmpFile);
460 switch (type) {
461 case PSX_EXE:
462 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
463 section_address = SWAP32(tmpHead.t_addr);
464 section_size = SWAP32(tmpHead.t_size);
465 mem = PSXM(section_address);
466 if (mem != NULL) {
467 fseek(tmpFile, 0x800, SEEK_SET);
468 fread_to_ram(mem, section_size, 1, tmpFile);
469 psxCpu->Clear(section_address, section_size / 4);
470 }
471 fclose(tmpFile);
472 psxRegs.pc = SWAP32(tmpHead.pc0);
473 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
474 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
475 if (psxRegs.GPR.n.sp == 0)
476 psxRegs.GPR.n.sp = 0x801fff00;
477 retval = 0;
478 break;
479 case CPE_EXE:
480 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
481 do {
482 fread(&opcode, 1, 1, tmpFile);
483 switch (opcode) {
484 case 1: /* Section loading */
485 fread(&section_address, 4, 1, tmpFile);
486 fread(&section_size, 4, 1, tmpFile);
487 section_address = SWAPu32(section_address);
488 section_size = SWAPu32(section_size);
489#ifdef EMU_LOG
490 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
491#endif
492 mem = PSXM(section_address);
493 if (mem != NULL) {
494 fread_to_ram(mem, section_size, 1, tmpFile);
495 psxCpu->Clear(section_address, section_size / 4);
496 }
497 break;
498 case 3: /* register loading (PC only?) */
499 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
500 fread(&psxRegs.pc, 4, 1, tmpFile);
501 psxRegs.pc = SWAPu32(psxRegs.pc);
502 break;
503 case 0: /* End of file */
504 break;
505 default:
506 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
507 retval = -1;
508 break;
509 }
510 } while (opcode != 0 && retval == 0);
511 break;
512 case COFF_EXE:
513 SysPrintf(_("COFF files not supported.\n"));
514 retval = -1;
515 break;
516 case INVALID_EXE:
517 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
518 SysPrintf(_("(did you forget -cdfile ?)\n"));
519 retval = -1;
520 break;
521 }
522 }
523
524 if (retval != 0) {
525 CdromId[0] = '\0';
526 CdromLabel[0] = '\0';
527 }
528
529 return retval;
530}
531
532// STATES
533
534static void *zlib_open(const char *name, const char *mode)
535{
536 return gzopen(name, mode);
537}
538
539static int zlib_read(void *file, void *buf, u32 len)
540{
541 return gzread(file, buf, len);
542}
543
544static int zlib_write(void *file, const void *buf, u32 len)
545{
546 return gzwrite(file, buf, len);
547}
548
549static long zlib_seek(void *file, long offs, int whence)
550{
551 return gzseek(file, offs, whence);
552}
553
554static void zlib_close(void *file)
555{
556 gzclose(file);
557}
558
559struct PcsxSaveFuncs SaveFuncs = {
560 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
561};
562
563static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
564
565// Savestate Versioning!
566// If you make changes to the savestate version, please increment the value below.
567static const u32 SaveVersion = 0x8b410006;
568
569int SaveState(const char *file) {
570 void *f;
571 GPUFreeze_t *gpufP;
572 SPUFreeze_t *spufP;
573 int Size;
574 unsigned char *pMem;
575
576 f = SaveFuncs.open(file, "wb");
577 if (f == NULL) return -1;
578
579 new_dyna_before_save();
580
581 SaveFuncs.write(f, (void *)PcsxHeader, 32);
582 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
583 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
584
585 pMem = (unsigned char *)malloc(128 * 96 * 3);
586 if (pMem == NULL) return -1;
587 GPU_getScreenPic(pMem);
588 SaveFuncs.write(f, pMem, 128 * 96 * 3);
589 free(pMem);
590
591 if (Config.HLE)
592 psxBiosFreeze(1);
593
594 SaveFuncs.write(f, psxM, 0x00200000);
595 SaveFuncs.write(f, psxR, 0x00080000);
596 SaveFuncs.write(f, psxH, 0x00010000);
597 SaveFuncs.write(f, (void *)&psxRegs, sizeof(psxRegs));
598
599 // gpu
600 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
601 gpufP->ulFreezeVersion = 1;
602 GPU_freeze(1, gpufP);
603 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
604 free(gpufP);
605
606 // spu
607 spufP = (SPUFreeze_t *) malloc(16);
608 SPU_freeze(2, spufP, psxRegs.cycle);
609 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
610 free(spufP);
611 spufP = (SPUFreeze_t *) malloc(Size);
612 SPU_freeze(1, spufP, psxRegs.cycle);
613 SaveFuncs.write(f, spufP, Size);
614 free(spufP);
615
616 sioFreeze(f, 1);
617 cdrFreeze(f, 1);
618 psxHwFreeze(f, 1);
619 psxRcntFreeze(f, 1);
620 mdecFreeze(f, 1);
621 new_dyna_freeze(f, 1);
622
623 SaveFuncs.close(f);
624
625 new_dyna_after_save();
626
627 return 0;
628}
629
630int LoadState(const char *file) {
631 void *f;
632 GPUFreeze_t *gpufP;
633 SPUFreeze_t *spufP;
634 int Size;
635 char header[32];
636 u32 version;
637 boolean hle;
638
639 f = SaveFuncs.open(file, "rb");
640 if (f == NULL) return -1;
641
642 SaveFuncs.read(f, header, sizeof(header));
643 SaveFuncs.read(f, &version, sizeof(u32));
644 SaveFuncs.read(f, &hle, sizeof(boolean));
645
646 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
647 SaveFuncs.close(f);
648 return -1;
649 }
650 Config.HLE = hle;
651
652 if (Config.HLE)
653 psxBiosInit();
654
655 psxCpu->Reset();
656 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
657
658 SaveFuncs.read(f, psxM, 0x00200000);
659 SaveFuncs.read(f, psxR, 0x00080000);
660 SaveFuncs.read(f, psxH, 0x00010000);
661 SaveFuncs.read(f, (void *)&psxRegs, sizeof(psxRegs));
662
663 if (Config.HLE)
664 psxBiosFreeze(0);
665
666 // gpu
667 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
668 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
669 GPU_freeze(0, gpufP);
670 free(gpufP);
671 if (HW_GPU_STATUS == 0)
672 HW_GPU_STATUS = GPU_readStatus();
673
674 // spu
675 SaveFuncs.read(f, &Size, 4);
676 spufP = (SPUFreeze_t *)malloc(Size);
677 SaveFuncs.read(f, spufP, Size);
678 SPU_freeze(0, spufP, psxRegs.cycle);
679 free(spufP);
680
681 sioFreeze(f, 0);
682 cdrFreeze(f, 0);
683 psxHwFreeze(f, 0);
684 psxRcntFreeze(f, 0);
685 mdecFreeze(f, 0);
686 new_dyna_freeze(f, 0);
687
688 SaveFuncs.close(f);
689
690 return 0;
691}
692
693int CheckState(const char *file) {
694 void *f;
695 char header[32];
696 u32 version;
697 boolean hle;
698
699 f = SaveFuncs.open(file, "rb");
700 if (f == NULL) return -1;
701
702 SaveFuncs.read(f, header, sizeof(header));
703 SaveFuncs.read(f, &version, sizeof(u32));
704 SaveFuncs.read(f, &hle, sizeof(boolean));
705
706 SaveFuncs.close(f);
707
708 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
709 return -1;
710
711 return 0;
712}
713
714// NET Function Helpers
715
716int SendPcsxInfo() {
717 if (NET_recvData == NULL || NET_sendData == NULL)
718 return 0;
719
720 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
721 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
722 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
723 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
724 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
725 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
726
727 return 0;
728}
729
730int RecvPcsxInfo() {
731 int tmp;
732
733 if (NET_recvData == NULL || NET_sendData == NULL)
734 return 0;
735
736 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
737 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
738 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
739 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
740 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
741
742 SysUpdate();
743
744 tmp = Config.Cpu;
745 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
746 if (tmp != Config.Cpu) {
747 psxCpu->Shutdown();
748#ifdef PSXREC
749 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
750 else psxCpu = &psxRec;
751#else
752 psxCpu = &psxInt;
753#endif
754 if (psxCpu->Init() == -1) {
755 SysClose(); return -1;
756 }
757 psxCpu->Reset();
758 }
759
760 return 0;
761}
762
763// remove the leading and trailing spaces in a string
764void trim(char *str) {
765 int pos = 0;
766 char *dest = str;
767
768 // skip leading blanks
769 while (str[pos] <= ' ' && str[pos] > 0)
770 pos++;
771
772 while (str[pos]) {
773 *(dest++) = str[pos];
774 pos++;
775 }
776
777 *(dest--) = '\0'; // store the null
778
779 // remove trailing blanks
780 while (dest >= str && *dest <= ' ' && *dest > 0)
781 *(dest--) = '\0';
782}
783
784// lookup table for crc calculation
785static unsigned short crctab[256] = {
786 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
787 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
788 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
789 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
790 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
791 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
792 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
793 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
794 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
795 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
796 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
797 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
798 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
799 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
800 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
801 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
802 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
803 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
804 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
805 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
806 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
807 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
808 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
809 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
810 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
811 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
812 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
813 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
814 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
815};
816
817u16 calcCrc(u8 *d, int len) {
818 u16 crc = 0;
819 int i;
820
821 for (i = 0; i < len; i++) {
822 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
823 }
824
825 return ~crc;
826}