+
+fail_io:
+#ifndef NDEBUG
+ SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+ fclose(ppffile);
+}
+
+// redump.org SBI files, slightly different handling from PCSX-Reloaded
+unsigned char *sbi_sectors;
+int sbi_len;
+
+int LoadSBI(const char *fname, int sector_count) {
+ int good_sectors = 0;
+ int clean_eof = 0;
+ char buffer[16];
+ FILE *sbihandle;
+ u8 sbitime[3], t;
+ int s;
+
+ sbihandle = fopen(fname, "rb");
+ if (sbihandle == NULL)
+ return -1;
+
+ sbi_len = (sector_count + 7) / 8;
+ sbi_sectors = calloc(1, sbi_len);
+ if (sbi_sectors == NULL)
+ goto end;
+
+ // 4-byte SBI header
+ if (fread(buffer, 1, 4, sbihandle) != 4)
+ goto end;
+
+ while (1) {
+ s = fread(sbitime, 1, 3, sbihandle);
+ if (s != 3)
+ {
+ if (s == 0)
+ clean_eof = 1;
+ break;
+ }
+ s = MSF2SECT(btoi(sbitime[0]), btoi(sbitime[1]), btoi(sbitime[2]));
+ if (s < sector_count) {
+ sbi_sectors[s >> 3] |= 1 << (s&7);
+ good_sectors++;
+ }
+ else
+ SysPrintf(_("SBI sector %d >= %d?\n"), s, sector_count);
+
+ // skip to the next record
+ if (fread(&t, 1, sizeof(t), sbihandle) != sizeof(t))
+ break;
+ s = -1;
+ switch (t) {
+ default:
+ case 1:
+ s = 10;
+ break;
+ case 2:
+ case 3:
+ s = 3;
+ break;
+ }
+ if (s < 0)
+ break;
+ if (fseek(sbihandle, s, SEEK_CUR))
+ break;
+ }
+
+end:
+ if (!clean_eof)
+ SysPrintf(_("SBI: parse failure at 0x%lx\n"), ftell(sbihandle));
+ if (!good_sectors) {
+ free(sbi_sectors);
+ sbi_sectors = NULL;
+ sbi_len = 0;
+ }
+ fclose(sbihandle);
+ return sbi_sectors ? 0 : -1;
+}
+
+void UnloadSBI(void) {
+ if (sbi_sectors) {
+ free(sbi_sectors);
+ sbi_sectors = NULL;
+ sbi_len = 0;
+ }