1 /* PPF Patch Support for PCSX-Reloaded
2 * Copyright (c) 2009, Wei Mingzhi <whistler_wmz@users.sf.net>.
4 * Based on P.E.Op.S CDR Plugin by Pete Bernert.
5 * Copyright (c) 2002, Pete Bernert.
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.
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.
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
22 #include "psxcommon.h"
27 typedef struct tagPPF_DATA {
31 struct tagPPF_DATA *pNext;
34 typedef struct tagPPF_CACHE {
36 struct tagPPF_DATA *pNext;
39 static PPF_CACHE *ppfCache = NULL;
40 static PPF_DATA *ppfHead = NULL, *ppfLast = NULL;
41 static int iPPFNum = 0;
43 // using a linked data list, and address array
44 static void FillPPFCache() {
54 if (p->addr != lastaddr) iPPFNum++;
59 if (iPPFNum <= 0) return;
61 pc = ppfCache = (PPF_CACHE *)malloc(iPPFNum * sizeof(PPF_CACHE));
62 if (pc == NULL) return;
69 if (p->addr != lastaddr) {
80 PPF_DATA *p = ppfHead;
91 if (ppfCache != NULL) free(ppfCache);
95 void CheckPPFCache(unsigned char *pB, unsigned char m, unsigned char s, unsigned char f) {
96 PPF_CACHE *pcstart, *pcend, *pcpos;
97 int addr = MSF2SECT(btoi(m), btoi(s), btoi(f)), pos, anz, start;
99 if (ppfCache == NULL) return;
102 if (addr < pcstart->addr) return;
103 pcend = ppfCache + iPPFNum;
104 if (addr > pcend->addr) return;
107 if (addr == pcend->addr) { pcpos = pcend; break; }
109 pcpos = pcstart + (pcend - pcstart) / 2;
110 if (pcpos == pcstart) break;
111 if (addr < pcpos->addr) {
115 if (addr > pcpos->addr) {
122 if (addr == pcpos->addr) {
123 PPF_DATA *p = pcpos->pNext;
124 while (p != NULL && p->addr == addr) {
125 pos = p->pos - (CD_FRAMESIZE_RAW - DATA_SIZE);
127 if (pos < 0) { start = -pos; pos = 0; anz -= start; }
129 memcpy(pB + pos, (unsigned char *)(p + 1) + start, anz);
135 static void AddToPPF(s32 ladr, s32 pos, s32 anz, unsigned char *ppfmem) {
136 if (ppfHead == NULL) {
137 ppfHead = (PPF_DATA *)malloc(sizeof(PPF_DATA) + anz);
138 if (ppfHead == NULL) return;
139 ppfHead->addr = ladr;
140 ppfHead->pNext = NULL;
143 memcpy(ppfHead + 1, ppfmem, anz);
147 PPF_DATA *p = ppfHead;
148 PPF_DATA *plast = NULL;
151 if (ladr > ppfLast->addr || (ladr == ppfLast->addr && pos > ppfLast->pos)) {
156 if (ladr < p->addr) break;
157 if (ladr == p->addr) {
158 while (p && ladr == p->addr && pos > p->pos) {
169 padd = (PPF_DATA *)malloc(sizeof(PPF_DATA) + anz);
170 if (padd == NULL) return;
175 memcpy(padd + 1, ppfmem, anz);
177 if (plast == NULL) ppfHead = padd;
178 else plast->pNext = padd;
180 if (padd->pNext == NULL) ppfLast = padd;
184 void BuildPPFCache() {
187 char method, undo = 0, blockcheck = 0;
189 unsigned char ppfmem[512];
190 char szPPF[MAXPATHLEN * 2];
191 int count, seekpos, pos;
192 u32 anz; // use 32-bit to avoid stupid overflows
197 if (CdromId[0] == '\0') return;
199 // Generate filename in the format of SLUS_123.45
200 buffer[0] = toupper(CdromId[0]);
201 buffer[1] = toupper(CdromId[1]);
202 buffer[2] = toupper(CdromId[2]);
203 buffer[3] = toupper(CdromId[3]);
205 buffer[5] = CdromId[4];
206 buffer[6] = CdromId[5];
207 buffer[7] = CdromId[6];
209 buffer[9] = CdromId[7];
210 buffer[10] = CdromId[8];
213 sprintf(szPPF, "%s%s", Config.PatchesDir, buffer);
215 ppffile = fopen(szPPF, "rb");
216 if (ppffile == NULL) return;
218 memset(buffer, 0, 5);
219 if (fread(buffer, 1, 3, ppffile) != 3)
222 if (strcmp(buffer, "PPF") != 0) {
223 SysPrintf(_("Invalid PPF patch: %s.\n"), szPPF);
228 fseek(ppffile, 5, SEEK_SET);
229 method = fgetc(ppffile);
233 fseek(ppffile, 0, SEEK_END);
234 count = ftell(ppffile);
240 fseek(ppffile, -8, SEEK_END);
242 memset(buffer, 0, 5);
243 if (fread(buffer, 1, 4, ppffile) != 4)
246 if (strcmp(".DIZ", buffer) != 0) {
249 if (fread(&dizlen, 1, 4, ppffile) != 4)
251 dizlen = SWAP32(dizlen);
255 fseek(ppffile, 0, SEEK_END);
256 count = ftell(ppffile);
270 fseek(ppffile, 57, SEEK_SET);
271 blockcheck = fgetc(ppffile);
272 undo = fgetc(ppffile);
274 fseek(ppffile, -6, SEEK_END);
275 memset(buffer, 0, 5);
276 if (fread(buffer, 1, 4, ppffile) != 4)
280 if (strcmp(".DIZ", buffer) == 0) {
281 fseek(ppffile, -2, SEEK_END);
282 // TODO: Endian/size unsafe?
283 if (fread(&dizlen, 1, 2, ppffile) != 2)
285 dizlen = SWAP32(dizlen);
289 fseek(ppffile, 0, SEEK_END);
290 count = ftell(ppffile);
304 SysPrintf(_("Unsupported PPF version (%d).\n"), method + 1);
308 // now do the data reading
310 fseek(ppffile, seekpos, SEEK_SET);
311 if (fread(&pos, 1, sizeof(pos), ppffile) != sizeof(pos))
316 // skip 4 bytes on ppf3 (no int64 support here)
317 if (fread(buffer, 1, 4, ppffile) != 4)
321 anz = fgetc(ppffile);
322 if (fread(ppfmem, 1, anz, ppffile) != anz)
325 ladr = pos / CD_FRAMESIZE_RAW;
326 off = pos % CD_FRAMESIZE_RAW;
328 if (off + anz > CD_FRAMESIZE_RAW) {
329 anx = off + anz - CD_FRAMESIZE_RAW;
330 anz -= (unsigned char)anx;
331 AddToPPF(ladr + 1, 0, anx, &ppfmem[anz]);
334 AddToPPF(ladr, off, anz, ppfmem); // add to link list
337 if (undo) anz += anz;
341 seekpos = seekpos + 5 + anz;
342 count = count - 5 - anz;
343 } while (count != 0); // loop til end
347 FillPPFCache(); // build address array
349 SysPrintf(_("Loaded PPF %d.0 patch: %s.\n"), method + 1, szPPF);
353 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
358 // redump.org SBI files, slightly different handling from PCSX-Reloaded
359 unsigned char *sbi_sectors;
362 int LoadSBI(const char *fname, int sector_count) {
363 int good_sectors = 0;
370 sbihandle = fopen(fname, "rb");
371 if (sbihandle == NULL)
374 sbi_len = (sector_count + 7) / 8;
375 sbi_sectors = calloc(1, sbi_len);
376 if (sbi_sectors == NULL)
380 if (fread(buffer, 1, 4, sbihandle) != 4)
384 s = fread(sbitime, 1, 3, sbihandle);
391 s = MSF2SECT(btoi(sbitime[0]), btoi(sbitime[1]), btoi(sbitime[2]));
392 if (s < sector_count) {
393 sbi_sectors[s >> 3] |= 1 << (s&7);
397 SysPrintf(_("SBI sector %d >= %d?\n"), s, sector_count);
399 // skip to the next record
400 if (fread(&t, 1, sizeof(t), sbihandle) != sizeof(t))
415 if (fseek(sbihandle, s, SEEK_CUR))
421 SysPrintf(_("SBI: parse failure at 0x%lx\n"), ftell(sbihandle));
428 return sbi_sectors ? 0 : -1;
431 void UnloadSBI(void) {