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