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