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