misc: patch some issues indicated by clang
[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
81dbbf4c 24#include <stddef.h>
ef79bbde
P
25#include "misc.h"
26#include "cdrom.h"
27#include "mdec.h"
ddbaf678 28#include "gpu.h"
ef79bbde 29#include "ppf.h"
eedfe806 30#include "database.h"
496d88d4 31#include <zlib.h>
ef79bbde
P
32
33char CdromId[10] = "";
34char 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
44struct 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
1c654475 58static void mmssdd( char *b, char *p )
ef79bbde
P
59{
60 int m, s, d;
1c654475 61 unsigned char *ub = (void *)b;
62 int block = (ub[3] << 24) | (ub[2] << 16) | (ub[1] << 8) | ub[0];
ef79bbde
P
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() \
415213c9 93 if (!CDR_readTrack(time)) return -1; \
305c8c93 94 buf = (void *)CDR_getBuffer(); \
95 if (buf == NULL) return -1; \
96 else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
ef79bbde
P
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
305c8c93 106int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
ef79bbde 107 struct iso_directory_record *dir;
5be6eaeb 108 int retval = -1;
305c8c93 109 u8 ddir[4096];
ef79bbde
P
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 }
1c2c2bfb 122 i += (u8)dir->length[0];
ef79bbde
P
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);
5be6eaeb 138 retval = 0;
ef79bbde
P
139 break;
140 }
141 }
142 }
5be6eaeb 143 return retval;
ef79bbde
P
144}
145
f3a78e7e 146static const unsigned int gpu_ctl_def[] = {
147 0x00000000, 0x01000000, 0x03000000, 0x04000000,
148 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
149};
150
151static const unsigned int gpu_data_def[] = {
152 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
153 0xe5001000, 0xe6000000,
154 0x02000000, 0x00000000, 0x01ff03ff,
155};
156
157static 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
ef79bbde
P
168int LoadCdrom() {
169 EXE_HEADER tmpHead;
170 struct iso_directory_record *dir;
171 u8 time[4], *buf;
172 u8 mdir[4096];
305c8c93 173 char exename[256];
ef79bbde 174
f3a78e7e 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
ef79bbde 179 if (!Config.HLE) {
f3a78e7e 180 // skip BIOS logos
ef79bbde
P
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
9a9bcd78 207 sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 208 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 209 sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde 210 if (GetCdromFile(mdir, time, exename) == -1) {
305c8c93 211 char *ptr = strstr((char *)buf + 12, "cdrom:");
ef79bbde
P
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
ebe6ff2b 241 psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
7bbabe80 242 psxCpu->Reset();
ebe6ff2b 243
ef79bbde 244 // Read the rest of the main executable
ebe6ff2b 245 while (tmpHead.t_size & ~2047) {
ef79bbde
P
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
260int LoadCdromFile(const char *filename, EXE_HEADER *head) {
261 struct iso_directory_record *dir;
262 u8 time[4],*buf;
305c8c93 263 u8 mdir[4096];
264 char exename[256];
ef79bbde 265 u32 size, addr;
305c8c93 266 void *mem;
ef79bbde 267
9a9bcd78 268 sscanf(filename, "cdrom:\\%255s", exename);
ef79bbde
P
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
ebe6ff2b 289 psxCpu->Clear(addr, size / 4);
7bbabe80 290 psxCpu->Reset();
ebe6ff2b 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];
e06ee7f4 313 int i, len, c;
ef79bbde
P
314
315 FreePPFCache();
316
317 time[0] = itob(0);
318 time[1] = itob(2);
319 time[2] = itob(0x10);
320
321 READTRACK();
322
e06ee7f4 323 memset(CdromLabel, 0, sizeof(CdromLabel));
324 memset(CdromId, 0, sizeof(CdromId));
325 memset(exename, 0, sizeof(exename));
ef79bbde
P
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
9a9bcd78 339 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 340 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 341 sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde
P
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') {
e06ee7f4 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];
ef79bbde
P
372 }
373 }
374
0e2e3f49 375 if (CdromId[0] == '\0')
376 strcpy(CdromId, "SLUS99999");
377
ef79bbde 378 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
40337130 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.
ef79bbde
P
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);
e06ee7f4 395 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
eedfe806 396
397 Apply_Hacks_Cdrom();
ef79bbde
P
398
399 BuildPPFCache();
400
401 return 0;
402}
403
404static 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
96bef96f 429// temporary pandora workaround..
430// FIXME: remove
431size_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
ef79bbde
P
445int 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;
ebe6ff2b 452 void *mem;
ef79bbde
P
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);
ebe6ff2b 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);
96bef96f 471 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 472 psxCpu->Clear(section_address, section_size / 4);
473 }
ef79bbde
P
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
ebe6ff2b 495 mem = PSXM(section_address);
496 if (mem != NULL) {
96bef96f 497 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 498 psxCpu->Clear(section_address, section_size / 4);
499 }
ef79bbde
P
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:
8f00f96c 520 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
521 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
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
496d88d4 537static void *zlib_open(const char *name, const char *mode)
538{
539 return gzopen(name, mode);
540}
541
542static int zlib_read(void *file, void *buf, u32 len)
543{
544 return gzread(file, buf, len);
545}
546
547static int zlib_write(void *file, const void *buf, u32 len)
548{
549 return gzwrite(file, buf, len);
550}
551
552static long zlib_seek(void *file, long offs, int whence)
553{
554 return gzseek(file, offs, whence);
555}
556
557static void zlib_close(void *file)
558{
559 gzclose(file);
560}
561
562struct PcsxSaveFuncs SaveFuncs = {
563 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
564};
565
ef79bbde
P
566static 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.
df656dde 570static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
571
572int SaveState(const char *file) {
496d88d4 573 void *f;
ef79bbde
P
574 GPUFreeze_t *gpufP;
575 SPUFreeze_t *spufP;
576 int Size;
577 unsigned char *pMem;
578
496d88d4 579 f = SaveFuncs.open(file, "wb");
ef79bbde
P
580 if (f == NULL) return -1;
581
03f55e6b 582 new_dyna_before_save();
52082bc1 583
496d88d4 584 SaveFuncs.write(f, (void *)PcsxHeader, 32);
585 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
586 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
587
588 pMem = (unsigned char *)malloc(128 * 96 * 3);
589 if (pMem == NULL) return -1;
590 GPU_getScreenPic(pMem);
496d88d4 591 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
592 free(pMem);
593
594 if (Config.HLE)
595 psxBiosFreeze(1);
596
496d88d4 597 SaveFuncs.write(f, psxM, 0x00200000);
598 SaveFuncs.write(f, psxR, 0x00080000);
599 SaveFuncs.write(f, psxH, 0x00010000);
81dbbf4c 600 // only partial save of psxRegisters to maintain savestate compat
601 SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
ef79bbde
P
602
603 // gpu
604 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
605 gpufP->ulFreezeVersion = 1;
606 GPU_freeze(1, gpufP);
496d88d4 607 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
608 free(gpufP);
609
610 // spu
611 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 612 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 613 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
614 free(spufP);
615 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 616 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 617 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
618 free(spufP);
619
620 sioFreeze(f, 1);
621 cdrFreeze(f, 1);
622 psxHwFreeze(f, 1);
623 psxRcntFreeze(f, 1);
624 mdecFreeze(f, 1);
03f55e6b 625 new_dyna_freeze(f, 1);
ef79bbde 626
496d88d4 627 SaveFuncs.close(f);
ef79bbde 628
5b8c000f 629 new_dyna_after_save();
630
ef79bbde
P
631 return 0;
632}
633
634int LoadState(const char *file) {
496d88d4 635 void *f;
ef79bbde
P
636 GPUFreeze_t *gpufP;
637 SPUFreeze_t *spufP;
638 int Size;
639 char header[32];
640 u32 version;
641 boolean hle;
642
496d88d4 643 f = SaveFuncs.open(file, "rb");
ef79bbde
P
644 if (f == NULL) return -1;
645
496d88d4 646 SaveFuncs.read(f, header, sizeof(header));
647 SaveFuncs.read(f, &version, sizeof(u32));
648 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 649
33f56da1 650 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 651 SaveFuncs.close(f);
ef79bbde
P
652 return -1;
653 }
33f56da1 654 Config.HLE = hle;
655
656 if (Config.HLE)
657 psxBiosInit();
ef79bbde
P
658
659 psxCpu->Reset();
496d88d4 660 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 661
496d88d4 662 SaveFuncs.read(f, psxM, 0x00200000);
663 SaveFuncs.read(f, psxR, 0x00080000);
664 SaveFuncs.read(f, psxH, 0x00010000);
81dbbf4c 665 SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
666 psxRegs.gteBusyCycle = psxRegs.cycle;
ef79bbde
P
667
668 if (Config.HLE)
669 psxBiosFreeze(0);
670
671 // gpu
672 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 673 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
674 GPU_freeze(0, gpufP);
675 free(gpufP);
ddbaf678 676 if (HW_GPU_STATUS == 0)
086adfff 677 HW_GPU_STATUS = SWAP32(GPU_readStatus());
ef79bbde
P
678
679 // spu
496d88d4 680 SaveFuncs.read(f, &Size, 4);
ef79bbde 681 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 682 SaveFuncs.read(f, spufP, Size);
650adfd2 683 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
684 free(spufP);
685
686 sioFreeze(f, 0);
687 cdrFreeze(f, 0);
688 psxHwFreeze(f, 0);
689 psxRcntFreeze(f, 0);
690 mdecFreeze(f, 0);
03f55e6b 691 new_dyna_freeze(f, 0);
ef79bbde 692
496d88d4 693 SaveFuncs.close(f);
ef79bbde
P
694
695 return 0;
696}
697
698int CheckState(const char *file) {
496d88d4 699 void *f;
ef79bbde
P
700 char header[32];
701 u32 version;
702 boolean hle;
703
496d88d4 704 f = SaveFuncs.open(file, "rb");
ef79bbde
P
705 if (f == NULL) return -1;
706
496d88d4 707 SaveFuncs.read(f, header, sizeof(header));
708 SaveFuncs.read(f, &version, sizeof(u32));
709 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 710
496d88d4 711 SaveFuncs.close(f);
ef79bbde 712
33f56da1 713 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
714 return -1;
715
716 return 0;
717}
718
719// NET Function Helpers
720
721int 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
735int 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();
41e82ad4 753#ifndef DRC_DISABLE
ef79bbde
P
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
769void 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
790static 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
822u16 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}