drc: adjust ld_use_hazard
[pcsx_rearmed.git] / libpcsxcore / ppf.c
CommitLineData
ef79bbde
P
1/* PPF Patch Support for PCSX-Reloaded
2 * Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
3 *
4 * Based on P.E.Op.S CDR Plugin by Pete Bernert.
5 * Copyright (c) 2002, Pete Bernert.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA
20 */
21
22#include "psxcommon.h"
23#include "ppf.h"
24#include "cdrom.h"
25
26typedef struct tagPPF_DATA {
27 s32 addr;
28 s32 pos;
29 s32 anz;
30 struct tagPPF_DATA *pNext;
31} PPF_DATA;
32
33typedef struct tagPPF_CACHE {
34 s32 addr;
35 struct tagPPF_DATA *pNext;
36} PPF_CACHE;
37
38static PPF_CACHE *ppfCache = NULL;
39static PPF_DATA *ppfHead = NULL, *ppfLast = NULL;
40static int iPPFNum = 0;
41
42// using a linked data list, and address array
43static void FillPPFCache() {
44 PPF_DATA *p;
45 PPF_CACHE *pc;
46 s32 lastaddr;
47
48 p = ppfHead;
49 lastaddr = -1;
50 iPPFNum = 0;
51
52 while (p != NULL) {
53 if (p->addr != lastaddr) iPPFNum++;
54 lastaddr = p->addr;
55 p = p->pNext;
56 }
57
58 if (iPPFNum <= 0) return;
59
60 pc = ppfCache = (PPF_CACHE *)malloc(iPPFNum * sizeof(PPF_CACHE));
cfa5a2af 61 if (pc == NULL) return;
ef79bbde
P
62
63 iPPFNum--;
64 p = ppfHead;
65 lastaddr = -1;
66
67 while (p != NULL) {
68 if (p->addr != lastaddr) {
69 pc->addr = p->addr;
70 pc->pNext = p;
71 pc++;
72 }
73 lastaddr = p->addr;
74 p = p->pNext;
75 }
76}
77
78void FreePPFCache() {
79 PPF_DATA *p = ppfHead;
80 void *pn;
81
82 while (p != NULL) {
83 pn = p->pNext;
84 free(p);
85 p = (PPF_DATA *)pn;
86 }
87 ppfHead = NULL;
88 ppfLast = NULL;
89
90 if (ppfCache != NULL) free(ppfCache);
91 ppfCache = NULL;
92}
93
94void CheckPPFCache(unsigned char *pB, unsigned char m, unsigned char s, unsigned char f) {
95 PPF_CACHE *pcstart, *pcend, *pcpos;
96 int addr = MSF2SECT(btoi(m), btoi(s), btoi(f)), pos, anz, start;
97
98 if (ppfCache == NULL) return;
99
100 pcstart = ppfCache;
101 if (addr < pcstart->addr) return;
102 pcend = ppfCache + iPPFNum;
103 if (addr > pcend->addr) return;
104
105 while (1) {
106 if (addr == pcend->addr) { pcpos = pcend; break; }
107
108 pcpos = pcstart + (pcend - pcstart) / 2;
109 if (pcpos == pcstart) break;
110 if (addr < pcpos->addr) {
111 pcend = pcpos;
112 continue;
113 }
114 if (addr > pcpos->addr) {
115 pcstart = pcpos;
116 continue;
117 }
118 break;
119 }
120
121 if (addr == pcpos->addr) {
122 PPF_DATA *p = pcpos->pNext;
123 while (p != NULL && p->addr == addr) {
124 pos = p->pos - (CD_FRAMESIZE_RAW - DATA_SIZE);
125 anz = p->anz;
126 if (pos < 0) { start = -pos; pos = 0; anz -= start; }
127 else start = 0;
128 memcpy(pB + pos, (unsigned char *)(p + 1) + start, anz);
129 p = p->pNext;
130 }
131 }
132}
133
134static void AddToPPF(s32 ladr, s32 pos, s32 anz, unsigned char *ppfmem) {
135 if (ppfHead == NULL) {
136 ppfHead = (PPF_DATA *)malloc(sizeof(PPF_DATA) + anz);
cfa5a2af 137 if (ppfHead == NULL) return;
ef79bbde
P
138 ppfHead->addr = ladr;
139 ppfHead->pNext = NULL;
140 ppfHead->pos = pos;
141 ppfHead->anz = anz;
142 memcpy(ppfHead + 1, ppfmem, anz);
143 iPPFNum = 1;
144 ppfLast = ppfHead;
145 } else {
146 PPF_DATA *p = ppfHead;
147 PPF_DATA *plast = NULL;
148 PPF_DATA *padd;
149
150 if (ladr > ppfLast->addr || (ladr == ppfLast->addr && pos > ppfLast->pos)) {
151 p = NULL;
152 plast = ppfLast;
153 } else {
154 while (p != NULL) {
155 if (ladr < p->addr) break;
156 if (ladr == p->addr) {
157 while (p && ladr == p->addr && pos > p->pos) {
158 plast = p;
159 p = p->pNext;
160 }
161 break;
162 }
163 plast = p;
164 p = p->pNext;
165 }
166 }
167
168 padd = (PPF_DATA *)malloc(sizeof(PPF_DATA) + anz);
cfa5a2af 169 if (padd == NULL) return;
ef79bbde
P
170 padd->addr = ladr;
171 padd->pNext = p;
172 padd->pos = pos;
173 padd->anz = anz;
174 memcpy(padd + 1, ppfmem, anz);
175 iPPFNum++;
176 if (plast == NULL) ppfHead = padd;
177 else plast->pNext = padd;
178
179 if (padd->pNext == NULL) ppfLast = padd;
180 }
181}
182
183void BuildPPFCache() {
184 FILE *ppffile;
185 char buffer[12];
186 char method, undo = 0, blockcheck = 0;
187 int dizlen, dizyn;
188 unsigned char ppfmem[512];
7a8d521f 189 char szPPF[MAXPATHLEN * 2];
ef79bbde
P
190 int count, seekpos, pos;
191 u32 anz; // use 32-bit to avoid stupid overflows
192 s32 ladr, off, anx;
193
194 FreePPFCache();
195
4e44d6f6 196 if (CdromId[0] == '\0') return;
197
ef79bbde
P
198 // Generate filename in the format of SLUS_123.45
199 buffer[0] = toupper(CdromId[0]);
200 buffer[1] = toupper(CdromId[1]);
201 buffer[2] = toupper(CdromId[2]);
202 buffer[3] = toupper(CdromId[3]);
203 buffer[4] = '_';
204 buffer[5] = CdromId[4];
205 buffer[6] = CdromId[5];
206 buffer[7] = CdromId[6];
207 buffer[8] = '.';
208 buffer[9] = CdromId[7];
209 buffer[10] = CdromId[8];
210 buffer[11] = '\0';
211
212 sprintf(szPPF, "%s%s", Config.PatchesDir, buffer);
213
214 ppffile = fopen(szPPF, "rb");
215 if (ppffile == NULL) return;
216
217 memset(buffer, 0, 5);
7a8d521f 218 if (fread(buffer, 1, 3, ppffile) != 3)
219 goto fail_io;
ef79bbde
P
220
221 if (strcmp(buffer, "PPF") != 0) {
222 SysPrintf(_("Invalid PPF patch: %s.\n"), szPPF);
223 fclose(ppffile);
224 return;
225 }
226
227 fseek(ppffile, 5, SEEK_SET);
228 method = fgetc(ppffile);
229
230 switch (method) {
231 case 0: // ppf1
232 fseek(ppffile, 0, SEEK_END);
233 count = ftell(ppffile);
234 count -= 56;
235 seekpos = 56;
236 break;
237
238 case 1: // ppf2
239 fseek(ppffile, -8, SEEK_END);
240
241 memset(buffer, 0, 5);
7a8d521f 242 if (fread(buffer, 1, 4, ppffile) != 4)
243 goto fail_io;
ef79bbde
P
244
245 if (strcmp(".DIZ", buffer) != 0) {
246 dizyn = 0;
247 } else {
7a8d521f 248 if (fread(&dizlen, 1, 4, ppffile) != 4)
249 goto fail_io;
ef79bbde
P
250 dizlen = SWAP32(dizlen);
251 dizyn = 1;
252 }
253
254 fseek(ppffile, 0, SEEK_END);
255 count = ftell(ppffile);
256
257 if (dizyn == 0) {
258 count -= 1084;
259 seekpos = 1084;
260 } else {
261 count -= 1084;
262 count -= 38;
263 count -= dizlen;
264 seekpos = 1084;
265 }
266 break;
267
268 case 2: // ppf3
269 fseek(ppffile, 57, SEEK_SET);
270 blockcheck = fgetc(ppffile);
271 undo = fgetc(ppffile);
272
273 fseek(ppffile, -6, SEEK_END);
274 memset(buffer, 0, 5);
7a8d521f 275 if (fread(buffer, 1, 4, ppffile) != 4)
276 goto fail_io;
ef79bbde
P
277 dizlen = 0;
278
279 if (strcmp(".DIZ", buffer) == 0) {
280 fseek(ppffile, -2, SEEK_END);
7a8d521f 281 // TODO: Endian/size unsafe?
282 if (fread(&dizlen, 1, 2, ppffile) != 2)
283 goto fail_io;
ef79bbde
P
284 dizlen = SWAP32(dizlen);
285 dizlen += 36;
286 }
287
288 fseek(ppffile, 0, SEEK_END);
289 count = ftell(ppffile);
290 count -= dizlen;
291
292 if (blockcheck) {
293 seekpos = 1084;
294 count -= 1084;
295 } else {
296 seekpos = 60;
297 count -= 60;
298 }
299 break;
300
301 default:
302 fclose(ppffile);
303 SysPrintf(_("Unsupported PPF version (%d).\n"), method + 1);
304 return;
305 }
306
307 // now do the data reading
308 do {
309 fseek(ppffile, seekpos, SEEK_SET);
7a8d521f 310 if (fread(&pos, 1, sizeof(pos), ppffile) != sizeof(pos))
311 goto fail_io;
ef79bbde
P
312 pos = SWAP32(pos);
313
7a8d521f 314 if (method == 2) {
315 // skip 4 bytes on ppf3 (no int64 support here)
316 if (fread(buffer, 1, 4, ppffile) != 4)
317 goto fail_io;
318 }
ef79bbde
P
319
320 anz = fgetc(ppffile);
7a8d521f 321 if (fread(ppfmem, 1, anz, ppffile) != anz)
322 goto fail_io;
ef79bbde
P
323
324 ladr = pos / CD_FRAMESIZE_RAW;
325 off = pos % CD_FRAMESIZE_RAW;
326
327 if (off + anz > CD_FRAMESIZE_RAW) {
328 anx = off + anz - CD_FRAMESIZE_RAW;
329 anz -= (unsigned char)anx;
330 AddToPPF(ladr + 1, 0, anx, &ppfmem[anz]);
331 }
332
333 AddToPPF(ladr, off, anz, ppfmem); // add to link list
334
335 if (method == 2) {
336 if (undo) anz += anz;
337 anz += 4;
338 }
339
340 seekpos = seekpos + 5 + anz;
341 count = count - 5 - anz;
342 } while (count != 0); // loop til end
343
344 fclose(ppffile);
345
346 FillPPFCache(); // build address array
347
348 SysPrintf(_("Loaded PPF %d.0 patch: %s.\n"), method + 1, szPPF);
7a8d521f 349
350fail_io:
351#ifndef NDEBUG
352 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
353#endif
354 fclose(ppffile);
ef79bbde 355}
ae4e7dc9 356
357// redump.org SBI files, slightly different handling from PCSX-Reloaded
358unsigned char *sbi_sectors;
359
360int LoadSBI(const char *fname, int sector_count) {
4904809d 361 int good_sectors = 0;
362 int clean_eof = 0;
ab948f7e 363 char buffer[16];
ae4e7dc9 364 FILE *sbihandle;
eaa895dc 365 u8 sbitime[3], t;
ae4e7dc9 366 int s;
367
368 sbihandle = fopen(fname, "rb");
369 if (sbihandle == NULL)
370 return -1;
371
ae4e7dc9 372 sbi_sectors = calloc(1, sector_count / 8);
4904809d 373 if (sbi_sectors == NULL)
374 goto end;
ae4e7dc9 375
376 // 4-byte SBI header
7a8d521f 377 if (fread(buffer, 1, 4, sbihandle) != 4)
4904809d 378 goto end;
7a8d521f 379
eaa895dc 380 while (1) {
381 s = fread(sbitime, 1, 3, sbihandle);
382 if (s != 3)
4904809d 383 {
384 if (s == 0)
385 clean_eof = 1;
386 break;
387 }
388 s = MSF2SECT(btoi(sbitime[0]), btoi(sbitime[1]), btoi(sbitime[2]));
389 if (s < sector_count) {
390 sbi_sectors[s >> 3] |= 1 << (s&7);
391 good_sectors++;
392 }
393 else
394 SysPrintf(_("SBI sector %d >= %d?\n"), s, sector_count);
395
396 // skip to the next record
7a8d521f 397 if (fread(&t, 1, sizeof(t), sbihandle) != sizeof(t))
4904809d 398 break;
399 s = -1;
eaa895dc 400 switch (t) {
401 default:
402 case 1:
403 s = 10;
404 break;
405 case 2:
406 case 3:
407 s = 3;
408 break;
409 }
4904809d 410 if (s < 0)
411 break;
412 if (fseek(sbihandle, s, SEEK_CUR))
413 break;
ae4e7dc9 414 }
415
416 fclose(sbihandle);
ae4e7dc9 417 return 0;
7a8d521f 418
4904809d 419end:
420 if (!clean_eof)
421 SysPrintf(_("SBI: parse failure at 0x%lx\n"), ftell(sbihandle));
422 if (!good_sectors) {
423 free(sbi_sectors);
424 sbi_sectors = NULL;
425 }
7a8d521f 426 fclose(sbihandle);
4904809d 427 return sbi_sectors ? 0 : -1;
ae4e7dc9 428}
429
430void UnloadSBI(void) {
431 if (sbi_sectors) {
432 free(sbi_sectors);
433 sbi_sectors = NULL;
434 }
435}