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