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