Rewrite rgbfix to perform most actions in memory.

Limit file operations to a small number that can be reasonably checked,
and do the majority of the actual work on a buffered header in memory
where operations won't fail.
This commit is contained in:
Anthony J. Bentley
2018-04-05 00:00:22 -06:00
parent 4d13d57491
commit 8a559beeb8

View File

@@ -207,9 +207,17 @@ int main(int argc, char *argv[])
err(1, "Error opening file %s", argv[argc - 1]); err(1, "Error opening file %s", argv[argc - 1]);
/* /*
* Write changes to ROM * Read ROM header
*
* Offsets in the buffer are 0x100 less than the equivalent in ROM.
*/ */
uint8_t header[0x50];
if (fseek(rom, 0x100, SEEK_SET) != 0)
err(1, "Could not locate ROM header");
if (fread(header, sizeof(uint8_t), sizeof header, rom) != sizeof header)
err(1, "Could not read ROM header");
if (fixlogo || trashlogo) { if (fixlogo || trashlogo) {
/* /*
* Offset 0x1040x133: Nintendo Logo * Offset 0x1040x133: Nintendo Logo
@@ -236,8 +244,7 @@ int main(int argc, char *argv[])
for (int i = 0; i < sizeof(ninlogo); i++) for (int i = 0; i < sizeof(ninlogo); i++)
ninlogo[i] = ~ninlogo[i]; ninlogo[i] = ~ninlogo[i];
fseek(rom, 0x104, SEEK_SET); memcpy(header + 0x04, ninlogo, sizeof ninlogo);
fwrite(ninlogo, 1, 48, rom);
} }
if (settitle) { if (settitle) {
@@ -258,11 +265,10 @@ int main(int argc, char *argv[])
* characters may conflict with the title. * characters may conflict with the title.
*/ */
fseek(rom, 0x134, SEEK_SET); int n = snprintf((char *)header + 0x34, 16, "%s", title);
fwrite(title, 1, strlen(title) + 1, rom);
while (ftell(rom) < 0x143) for (int i = 16; i > n; i--)
fputc(0, rom); header[0x34 + i] = '\0';
} }
if (setid) { if (setid) {
@@ -272,8 +278,7 @@ int main(int argc, char *argv[])
* characters). * characters).
*/ */
fseek(rom, 0x13F, SEEK_SET); memcpy(header + 0x3F, id, 4);
fwrite(id, 1, 4, rom);
} }
if (colorcompatible) { if (colorcompatible) {
@@ -291,20 +296,12 @@ int main(int argc, char *argv[])
* may conflict. * may conflict.
*/ */
uint8_t byte; header[0x43] |= 1 << 7;
fseek(rom, 0x143, SEEK_SET);
byte = fgetc(rom);
byte |= 1 << 7;
if (coloronly) if (coloronly)
byte |= 1 << 6; header[0x43] |= 1 << 6;
if (byte & 0x3F) if (header[0x43] & 0x3F)
warnx("Color flag conflicts with game title"); warnx("Color flag conflicts with game title");
fseek(rom, 0x143, SEEK_SET);
fputc(byte, rom);
} }
if (setnewlicensee) { if (setnewlicensee) {
@@ -320,8 +317,8 @@ int main(int argc, char *argv[])
* as a Super Game Boy flag. * as a Super Game Boy flag.
*/ */
fseek(rom, 0x144, SEEK_SET); header[0x44] = newlicensee[0];
fwrite(newlicensee, 1, 2, rom); header[0x45] = newlicensee[1];
} }
if (super) { if (super) {
@@ -340,8 +337,7 @@ int main(int argc, char *argv[])
if (!setlicensee) if (!setlicensee)
warnx("You should probably set both '-s' and '-l 0x33'"); warnx("You should probably set both '-s' and '-l 0x33'");
fseek(rom, 0x146, SEEK_SET); header[0x46] = 3;
fputc(3, rom);
} }
if (setcartridge) { if (setcartridge) {
@@ -351,8 +347,7 @@ int main(int argc, char *argv[])
* external RAM, timer, rumble, or battery. * external RAM, timer, rumble, or battery.
*/ */
fseek(rom, 0x147, SEEK_SET); header[0x47] = cartridge;
fputc(cartridge, rom);
} }
if (resize) { if (resize) {
@@ -366,8 +361,10 @@ int main(int argc, char *argv[])
int headbyte; int headbyte;
uint8_t *buf; uint8_t *buf;
fseek(rom, 0, SEEK_END); if (fseek(rom, 0, SEEK_END) != 0)
romsize = ftell(rom); err(1, "Could not pad ROM file");
if ((romsize = ftell(rom)) == -1)
err(1, "Could not pad ROM file");
newsize = 0x8000; newsize = 0x8000;
headbyte = 0; headbyte = 0;
@@ -379,12 +376,13 @@ int main(int argc, char *argv[])
if (newsize > 0x800000) /* ROM is bigger than 8MiB */ if (newsize > 0x800000) /* ROM is bigger than 8MiB */
warnx("ROM size is bigger than 8MiB"); warnx("ROM size is bigger than 8MiB");
buf = malloc(newsize - romsize); if ((buf = malloc(newsize - romsize)) == NULL)
err(1, "Could not pad ROM file");
memset(buf, padvalue, newsize - romsize); memset(buf, padvalue, newsize - romsize);
fwrite(buf, 1, newsize - romsize, rom); if (fwrite(buf, 1, newsize - romsize, rom) != newsize - romsize)
err(1, "Could not pad ROM file");
fseek(rom, 0x148, SEEK_SET); header[0x48] = headbyte;
fputc(headbyte, rom);
free(buf); free(buf);
} }
@@ -394,8 +392,7 @@ int main(int argc, char *argv[])
* Offset 0x149: RAM Size * Offset 0x149: RAM Size
*/ */
fseek(rom, 0x149, SEEK_SET); header[0x49] = ramsize;
fputc(ramsize, rom);
} }
if (nonjapan) { if (nonjapan) {
@@ -403,8 +400,7 @@ int main(int argc, char *argv[])
* Offset 0x14A: Non-Japanese Region Flag * Offset 0x14A: Non-Japanese Region Flag
*/ */
fseek(rom, 0x14A, SEEK_SET); header[0x4A] = 1;
fputc(1, rom);
} }
if (setlicensee) { if (setlicensee) {
@@ -420,8 +416,7 @@ int main(int argc, char *argv[])
* See also: the New Licensee ID at 0x1440x145. * See also: the New Licensee ID at 0x1440x145.
*/ */
fseek(rom, 0x14B, SEEK_SET); header[0x4B] = licensee;
fputc(licensee, rom);
} }
if (setversion) { if (setversion) {
@@ -430,8 +425,7 @@ int main(int argc, char *argv[])
* Which version of the ROM this is. * Which version of the ROM this is.
*/ */
fseek(rom, 0x14C, SEEK_SET); header[0x4C] = version;
fputc(version, rom);
} }
if (fixheadsum || trashheadsum) { if (fixheadsum || trashheadsum) {
@@ -441,17 +435,26 @@ int main(int argc, char *argv[])
uint8_t headcksum = 0; uint8_t headcksum = 0;
fseek(rom, 0x134, SEEK_SET); for (int i = 0x34; i < 0x4D; ++i)
for (int i = 0; i < (0x14D - 0x134); ++i) headcksum = headcksum - header[i] - 1;
headcksum = headcksum - fgetc(rom) - 1;
if (trashheadsum) if (trashheadsum)
headcksum = ~headcksum; headcksum = ~headcksum;
fseek(rom, 0x14D, SEEK_SET); header[0x4D] = headcksum;
fputc(headcksum, rom);
} }
/*
* Before calculating the global checksum, we must write the modified
* header to the ROM.
*/
if (fseek(rom, 0x100, SEEK_SET) != 0)
err(1, "Could not locate header for writing");
if (fwrite(header, sizeof(uint8_t), sizeof header, rom) != sizeof header)
err(1, "Could not write modified ROM header");
if (fixglobalsum || trashglobalsum) { if (fixglobalsum || trashglobalsum) {
/* /*
* Offset 0x14E0x14F: Global Checksum * Offset 0x14E0x14F: Global Checksum
@@ -459,15 +462,19 @@ int main(int argc, char *argv[])
uint16_t globalcksum = 0; uint16_t globalcksum = 0;
rewind(rom); if (fseek(rom, 0, SEEK_SET) != 0)
for (int i = 0; i < 0x14E; ++i) err(1, "Could not start calculating global checksum");
globalcksum += fgetc(rom);
int i = 0;
int byte; int byte;
while ((byte = fgetc(rom)) != EOF) {
i++;
if (i != 0x150)
globalcksum += byte;
}
fseek(rom, 0x150, SEEK_SET); if (ferror(rom))
while ((byte = fgetc(rom)) != EOF) err(1, "Could not calculate global checksum");
globalcksum += byte;
if (trashglobalsum) if (trashglobalsum)
globalcksum = ~globalcksum; globalcksum = ~globalcksum;
@@ -475,9 +482,12 @@ int main(int argc, char *argv[])
fseek(rom, 0x14E, SEEK_SET); fseek(rom, 0x14E, SEEK_SET);
fputc(globalcksum >> 8, rom); fputc(globalcksum >> 8, rom);
fputc(globalcksum & 0xFF, rom); fputc(globalcksum & 0xFF, rom);
if (ferror(rom))
err(1, "Could not write global checksum");
} }
fclose(rom); if (fclose(rom) != 0)
err(1, "Could not complete ROM write");
return 0; return 0;
} }