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