mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Merge pull request #264 from inmemrgbfix
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. Signed-off-by: Antonio Niño Díaz <antonio_nd@outlook.com>
This commit is contained in:
114
src/fix/main.c
114
src/fix/main.c
@@ -207,9 +207,17 @@ int main(int argc, char *argv[])
|
||||
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) {
|
||||
/*
|
||||
* Offset 0x104–0x133: Nintendo Logo
|
||||
@@ -236,8 +244,7 @@ int main(int argc, char *argv[])
|
||||
for (int i = 0; i < sizeof(ninlogo); i++)
|
||||
ninlogo[i] = ~ninlogo[i];
|
||||
|
||||
fseek(rom, 0x104, SEEK_SET);
|
||||
fwrite(ninlogo, 1, 48, rom);
|
||||
memcpy(header + 0x04, ninlogo, sizeof ninlogo);
|
||||
}
|
||||
|
||||
if (settitle) {
|
||||
@@ -258,11 +265,10 @@ int main(int argc, char *argv[])
|
||||
* characters may conflict with the title.
|
||||
*/
|
||||
|
||||
fseek(rom, 0x134, SEEK_SET);
|
||||
fwrite(title, 1, strlen(title) + 1, rom);
|
||||
int n = snprintf((char *)header + 0x34, 16, "%s", title);
|
||||
|
||||
while (ftell(rom) < 0x143)
|
||||
fputc(0, rom);
|
||||
for (int i = 16; i > n; i--)
|
||||
header[0x34 + i] = '\0';
|
||||
}
|
||||
|
||||
if (setid) {
|
||||
@@ -272,8 +278,7 @@ int main(int argc, char *argv[])
|
||||
* characters).
|
||||
*/
|
||||
|
||||
fseek(rom, 0x13F, SEEK_SET);
|
||||
fwrite(id, 1, 4, rom);
|
||||
memcpy(header + 0x3F, id, 4);
|
||||
}
|
||||
|
||||
if (colorcompatible) {
|
||||
@@ -291,20 +296,12 @@ int main(int argc, char *argv[])
|
||||
* may conflict.
|
||||
*/
|
||||
|
||||
uint8_t byte;
|
||||
|
||||
fseek(rom, 0x143, SEEK_SET);
|
||||
byte = fgetc(rom);
|
||||
|
||||
byte |= 1 << 7;
|
||||
header[0x43] |= 1 << 7;
|
||||
if (coloronly)
|
||||
byte |= 1 << 6;
|
||||
header[0x43] |= 1 << 6;
|
||||
|
||||
if (byte & 0x3F)
|
||||
if (header[0x43] & 0x3F)
|
||||
warnx("Color flag conflicts with game title");
|
||||
|
||||
fseek(rom, 0x143, SEEK_SET);
|
||||
fputc(byte, rom);
|
||||
}
|
||||
|
||||
if (setnewlicensee) {
|
||||
@@ -320,8 +317,8 @@ int main(int argc, char *argv[])
|
||||
* as a Super Game Boy flag.
|
||||
*/
|
||||
|
||||
fseek(rom, 0x144, SEEK_SET);
|
||||
fwrite(newlicensee, 1, 2, rom);
|
||||
header[0x44] = newlicensee[0];
|
||||
header[0x45] = newlicensee[1];
|
||||
}
|
||||
|
||||
if (super) {
|
||||
@@ -340,8 +337,7 @@ int main(int argc, char *argv[])
|
||||
if (!setlicensee)
|
||||
warnx("You should probably set both '-s' and '-l 0x33'");
|
||||
|
||||
fseek(rom, 0x146, SEEK_SET);
|
||||
fputc(3, rom);
|
||||
header[0x46] = 3;
|
||||
}
|
||||
|
||||
if (setcartridge) {
|
||||
@@ -351,8 +347,7 @@ int main(int argc, char *argv[])
|
||||
* external RAM, timer, rumble, or battery.
|
||||
*/
|
||||
|
||||
fseek(rom, 0x147, SEEK_SET);
|
||||
fputc(cartridge, rom);
|
||||
header[0x47] = cartridge;
|
||||
}
|
||||
|
||||
if (resize) {
|
||||
@@ -366,8 +361,10 @@ int main(int argc, char *argv[])
|
||||
int headbyte;
|
||||
uint8_t *buf;
|
||||
|
||||
fseek(rom, 0, SEEK_END);
|
||||
romsize = ftell(rom);
|
||||
if (fseek(rom, 0, SEEK_END) != 0)
|
||||
err(1, "Could not pad ROM file");
|
||||
if ((romsize = ftell(rom)) == -1)
|
||||
err(1, "Could not pad ROM file");
|
||||
newsize = 0x8000;
|
||||
|
||||
headbyte = 0;
|
||||
@@ -382,11 +379,12 @@ int main(int argc, char *argv[])
|
||||
buf = malloc(newsize - romsize);
|
||||
if (buf == NULL)
|
||||
errx(1, "Couldn't allocate memory for padded ROM.");
|
||||
memset(buf, padvalue, newsize - romsize);
|
||||
fwrite(buf, 1, newsize - romsize, rom);
|
||||
|
||||
fseek(rom, 0x148, SEEK_SET);
|
||||
fputc(headbyte, rom);
|
||||
memset(buf, padvalue, newsize - romsize);
|
||||
if (fwrite(buf, 1, newsize - romsize, rom) != newsize - romsize)
|
||||
err(1, "Could not pad ROM file");
|
||||
|
||||
header[0x48] = headbyte;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
@@ -396,8 +394,7 @@ int main(int argc, char *argv[])
|
||||
* Offset 0x149: RAM Size
|
||||
*/
|
||||
|
||||
fseek(rom, 0x149, SEEK_SET);
|
||||
fputc(ramsize, rom);
|
||||
header[0x49] = ramsize;
|
||||
}
|
||||
|
||||
if (nonjapan) {
|
||||
@@ -405,8 +402,7 @@ int main(int argc, char *argv[])
|
||||
* Offset 0x14A: Non-Japanese Region Flag
|
||||
*/
|
||||
|
||||
fseek(rom, 0x14A, SEEK_SET);
|
||||
fputc(1, rom);
|
||||
header[0x4A] = 1;
|
||||
}
|
||||
|
||||
if (setlicensee) {
|
||||
@@ -422,8 +418,7 @@ int main(int argc, char *argv[])
|
||||
* See also: the New Licensee ID at 0x144–0x145.
|
||||
*/
|
||||
|
||||
fseek(rom, 0x14B, SEEK_SET);
|
||||
fputc(licensee, rom);
|
||||
header[0x4B] = licensee;
|
||||
}
|
||||
|
||||
if (setversion) {
|
||||
@@ -432,8 +427,7 @@ int main(int argc, char *argv[])
|
||||
* Which version of the ROM this is.
|
||||
*/
|
||||
|
||||
fseek(rom, 0x14C, SEEK_SET);
|
||||
fputc(version, rom);
|
||||
header[0x4C] = version;
|
||||
}
|
||||
|
||||
if (fixheadsum || trashheadsum) {
|
||||
@@ -443,17 +437,26 @@ int main(int argc, char *argv[])
|
||||
|
||||
uint8_t headcksum = 0;
|
||||
|
||||
fseek(rom, 0x134, SEEK_SET);
|
||||
for (int i = 0; i < (0x14D - 0x134); ++i)
|
||||
headcksum = headcksum - fgetc(rom) - 1;
|
||||
for (int i = 0x34; i < 0x4D; ++i)
|
||||
headcksum = headcksum - header[i] - 1;
|
||||
|
||||
if (trashheadsum)
|
||||
headcksum = ~headcksum;
|
||||
|
||||
fseek(rom, 0x14D, SEEK_SET);
|
||||
fputc(headcksum, rom);
|
||||
header[0x4D] = headcksum;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
/*
|
||||
* Offset 0x14E–0x14F: Global Checksum
|
||||
@@ -461,15 +464,19 @@ int main(int argc, char *argv[])
|
||||
|
||||
uint16_t globalcksum = 0;
|
||||
|
||||
rewind(rom);
|
||||
for (int i = 0; i < 0x14E; ++i)
|
||||
globalcksum += fgetc(rom);
|
||||
if (fseek(rom, 0, SEEK_SET) != 0)
|
||||
err(1, "Could not start calculating global checksum");
|
||||
|
||||
int i = 0;
|
||||
int byte;
|
||||
while ((byte = fgetc(rom)) != EOF) {
|
||||
i++;
|
||||
if (i != 0x150)
|
||||
globalcksum += byte;
|
||||
}
|
||||
|
||||
fseek(rom, 0x150, SEEK_SET);
|
||||
while ((byte = fgetc(rom)) != EOF)
|
||||
globalcksum += byte;
|
||||
if (ferror(rom))
|
||||
err(1, "Could not calculate global checksum");
|
||||
|
||||
if (trashglobalsum)
|
||||
globalcksum = ~globalcksum;
|
||||
@@ -477,9 +484,12 @@ int main(int argc, char *argv[])
|
||||
fseek(rom, 0x14E, SEEK_SET);
|
||||
fputc(globalcksum >> 8, 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user