mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Run clang-format on everything (#1332)
This commit is contained in:
412
src/fix/main.cpp
412
src/fix/main.cpp
@@ -1,7 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
@@ -14,7 +15,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "extern/getopt.hpp"
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "version.hpp"
|
||||
@@ -37,47 +37,46 @@ static const char *optstring = "Ccf:i:jk:l:m:n:Op:r:st:Vv";
|
||||
* over short opt matching
|
||||
*/
|
||||
static option const longopts[] = {
|
||||
{ "color-only", no_argument, nullptr, 'C' },
|
||||
{ "color-compatible", no_argument, nullptr, 'c' },
|
||||
{ "fix-spec", required_argument, nullptr, 'f' },
|
||||
{ "game-id", required_argument, nullptr, 'i' },
|
||||
{ "non-japanese", no_argument, nullptr, 'j' },
|
||||
{ "new-licensee", required_argument, nullptr, 'k' },
|
||||
{ "old-licensee", required_argument, nullptr, 'l' },
|
||||
{ "mbc-type", required_argument, nullptr, 'm' },
|
||||
{ "rom-version", required_argument, nullptr, 'n' },
|
||||
{ "overwrite", no_argument, nullptr, 'O' },
|
||||
{ "pad-value", required_argument, nullptr, 'p' },
|
||||
{ "ram-size", required_argument, nullptr, 'r' },
|
||||
{ "sgb-compatible", no_argument, nullptr, 's' },
|
||||
{ "title", required_argument, nullptr, 't' },
|
||||
{ "version", no_argument, nullptr, 'V' },
|
||||
{ "validate", no_argument, nullptr, 'v' },
|
||||
{ nullptr, no_argument, nullptr, 0 }
|
||||
{"color-only", no_argument, nullptr, 'C'},
|
||||
{"color-compatible", no_argument, nullptr, 'c'},
|
||||
{"fix-spec", required_argument, nullptr, 'f'},
|
||||
{"game-id", required_argument, nullptr, 'i'},
|
||||
{"non-japanese", no_argument, nullptr, 'j'},
|
||||
{"new-licensee", required_argument, nullptr, 'k'},
|
||||
{"old-licensee", required_argument, nullptr, 'l'},
|
||||
{"mbc-type", required_argument, nullptr, 'm'},
|
||||
{"rom-version", required_argument, nullptr, 'n'},
|
||||
{"overwrite", no_argument, nullptr, 'O'},
|
||||
{"pad-value", required_argument, nullptr, 'p'},
|
||||
{"ram-size", required_argument, nullptr, 'r'},
|
||||
{"sgb-compatible", no_argument, nullptr, 's'},
|
||||
{"title", required_argument, nullptr, 't'},
|
||||
{"version", no_argument, nullptr, 'V'},
|
||||
{"validate", no_argument, nullptr, 'v'},
|
||||
{nullptr, no_argument, nullptr, 0 }
|
||||
};
|
||||
|
||||
static void printUsage()
|
||||
{
|
||||
static void printUsage() {
|
||||
fputs(
|
||||
"Usage: rgbfix [-jOsVv] [-C | -c] [-f <fix_spec>] [-i <game_id>] [-k <licensee>]\n"
|
||||
" [-l <licensee_byte>] [-m <mbc_type>] [-n <rom_version>]\n"
|
||||
" [-p <pad_value>] [-r <ram_size>] [-t <title_str>] <file> ...\n"
|
||||
"Useful options:\n"
|
||||
" -m, --mbc-type <value> set the MBC type byte to this value; refer\n"
|
||||
" to the man page for a list of values\n"
|
||||
" -p, --pad-value <value> pad to the next valid size using this value\n"
|
||||
" -r, --ram-size <code> set the cart RAM size byte to this value\n"
|
||||
" -V, --version print RGBFIX version and exit\n"
|
||||
" -v, --validate fix the header logo and both checksums (-f lhg)\n"
|
||||
"\n"
|
||||
"For help, use `man rgbfix' or go to https://rgbds.gbdev.io/docs/\n",
|
||||
stderr);
|
||||
"Usage: rgbfix [-jOsVv] [-C | -c] [-f <fix_spec>] [-i <game_id>] [-k <licensee>]\n"
|
||||
" [-l <licensee_byte>] [-m <mbc_type>] [-n <rom_version>]\n"
|
||||
" [-p <pad_value>] [-r <ram_size>] [-t <title_str>] <file> ...\n"
|
||||
"Useful options:\n"
|
||||
" -m, --mbc-type <value> set the MBC type byte to this value; refer\n"
|
||||
" to the man page for a list of values\n"
|
||||
" -p, --pad-value <value> pad to the next valid size using this value\n"
|
||||
" -r, --ram-size <code> set the cart RAM size byte to this value\n"
|
||||
" -V, --version print RGBFIX version and exit\n"
|
||||
" -v, --validate fix the header logo and both checksums (-f lhg)\n"
|
||||
"\n"
|
||||
"For help, use `man rgbfix' or go to https://rgbds.gbdev.io/docs/\n",
|
||||
stderr
|
||||
);
|
||||
}
|
||||
|
||||
static uint8_t nbErrors;
|
||||
|
||||
static format_(printf, 1, 2) void report(char const *fmt, ...)
|
||||
{
|
||||
static format_(printf, 1, 2) void report(char const *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
@@ -89,7 +88,7 @@ static format_(printf, 1, 2) void report(char const *fmt, ...)
|
||||
}
|
||||
|
||||
enum MbcType {
|
||||
ROM = 0x00,
|
||||
ROM = 0x00,
|
||||
ROM_RAM = 0x08,
|
||||
ROM_RAM_BATTERY = 0x09,
|
||||
|
||||
@@ -153,13 +152,12 @@ enum MbcType {
|
||||
|
||||
// Error values
|
||||
MBC_NONE = UNSPECIFIED, // No MBC specified, do not act on it
|
||||
MBC_BAD, // Specified MBC does not exist / syntax error
|
||||
MBC_WRONG_FEATURES, // MBC incompatible with specified features
|
||||
MBC_BAD_RANGE, // MBC number out of range
|
||||
MBC_BAD, // Specified MBC does not exist / syntax error
|
||||
MBC_WRONG_FEATURES, // MBC incompatible with specified features
|
||||
MBC_BAD_RANGE, // MBC number out of range
|
||||
};
|
||||
|
||||
static void printAcceptedMBCNames()
|
||||
{
|
||||
static void printAcceptedMBCNames() {
|
||||
fputs("\tROM ($00) [aka ROM_ONLY]\n", stderr);
|
||||
fputs("\tMBC1 ($01), MBC1+RAM ($02), MBC1+RAM+BATTERY ($03)\n", stderr);
|
||||
fputs("\tMBC2 ($05), MBC2+BATTERY ($06)\n", stderr);
|
||||
@@ -188,8 +186,7 @@ static uint8_t tpp1Rev[2];
|
||||
/*
|
||||
* @return False on failure
|
||||
*/
|
||||
static bool readMBCSlice(char const *&name, char const *expected)
|
||||
{
|
||||
static bool readMBCSlice(char const *&name, char const *expected) {
|
||||
while (*expected) {
|
||||
char c = *name++;
|
||||
|
||||
@@ -207,8 +204,7 @@ static bool readMBCSlice(char const *&name, char const *expected)
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum MbcType parseMBC(char const *name)
|
||||
{
|
||||
static enum MbcType parseMBC(char const *name) {
|
||||
if (!strcasecmp(name, "help")) {
|
||||
fputs("Accepted MBC names:\n", stderr);
|
||||
printAcceptedMBCNames();
|
||||
@@ -242,10 +238,10 @@ static enum MbcType parseMBC(char const *name)
|
||||
ptr++;
|
||||
|
||||
#define tryReadSlice(expected) \
|
||||
do { \
|
||||
if (!readMBCSlice(ptr, expected)) \
|
||||
return MBC_BAD; \
|
||||
} while (0)
|
||||
do { \
|
||||
if (!readMBCSlice(ptr, expected)) \
|
||||
return MBC_BAD; \
|
||||
} while (0)
|
||||
|
||||
switch (*ptr++) {
|
||||
case 'R': // ROM / ROM_ONLY
|
||||
@@ -386,11 +382,11 @@ do { \
|
||||
|
||||
// Read "additional features"
|
||||
uint8_t features = 0;
|
||||
#define RAM 0x80
|
||||
#define BATTERY 0x40
|
||||
#define TIMER 0x20
|
||||
#define RUMBLE 0x10
|
||||
#define SENSOR 0x08
|
||||
#define RAM 0x80
|
||||
#define BATTERY 0x40
|
||||
#define TIMER 0x20
|
||||
#define RUMBLE 0x10
|
||||
#define SENSOR 0x08
|
||||
#define MULTIRUMBLE 0x04
|
||||
|
||||
for (;;) {
|
||||
@@ -498,8 +494,9 @@ do { \
|
||||
}
|
||||
static_assert(MBC3 + 1 == MBC3_RAM, "Enum sanity check failed!");
|
||||
static_assert(MBC3 + 2 == MBC3_RAM_BATTERY, "Enum sanity check failed!");
|
||||
static_assert(MBC3_TIMER_BATTERY + 1 == MBC3_TIMER_RAM_BATTERY,
|
||||
"Enum sanity check failed!");
|
||||
static_assert(
|
||||
MBC3_TIMER_BATTERY + 1 == MBC3_TIMER_RAM_BATTERY, "Enum sanity check failed!"
|
||||
);
|
||||
if (features == RAM)
|
||||
mbc++;
|
||||
else if (features == (RAM | BATTERY))
|
||||
@@ -516,8 +513,7 @@ do { \
|
||||
static_assert(MBC5 + 1 == MBC5_RAM, "Enum sanity check failed!");
|
||||
static_assert(MBC5 + 2 == MBC5_RAM_BATTERY, "Enum sanity check failed!");
|
||||
static_assert(MBC5_RUMBLE + 1 == MBC5_RUMBLE_RAM, "Enum sanity check failed!");
|
||||
static_assert(MBC5_RUMBLE + 2 == MBC5_RUMBLE_RAM_BATTERY,
|
||||
"Enum sanity check failed!");
|
||||
static_assert(MBC5_RUMBLE + 2 == MBC5_RUMBLE_RAM_BATTERY, "Enum sanity check failed!");
|
||||
if (features == RAM)
|
||||
mbc++;
|
||||
else if (features == (RAM | BATTERY))
|
||||
@@ -547,8 +543,9 @@ do { \
|
||||
|
||||
case TPP1:
|
||||
if (features & RAM)
|
||||
fprintf(stderr,
|
||||
"warning: TPP1 requests RAM implicitly if given a non-zero RAM size");
|
||||
fprintf(
|
||||
stderr, "warning: TPP1 requests RAM implicitly if given a non-zero RAM size"
|
||||
);
|
||||
if (features & BATTERY)
|
||||
mbc |= 0x08;
|
||||
if (features & TIMER)
|
||||
@@ -574,8 +571,7 @@ do { \
|
||||
}
|
||||
}
|
||||
|
||||
static char const *mbcName(enum MbcType type)
|
||||
{
|
||||
static char const *mbcName(enum MbcType type) {
|
||||
switch (type) {
|
||||
case ROM:
|
||||
return "ROM";
|
||||
@@ -673,8 +669,7 @@ static char const *mbcName(enum MbcType type)
|
||||
unreachable_();
|
||||
}
|
||||
|
||||
static bool hasRAM(enum MbcType type)
|
||||
{
|
||||
static bool hasRAM(enum MbcType type) {
|
||||
switch (type) {
|
||||
case ROM:
|
||||
case MBC1:
|
||||
@@ -685,7 +680,7 @@ static bool hasRAM(enum MbcType type)
|
||||
case MBC3_TIMER_BATTERY:
|
||||
case MBC5:
|
||||
case MBC5_RUMBLE:
|
||||
case MBC6: // TODO: not sure
|
||||
case MBC6: // TODO: not sure
|
||||
case BANDAI_TAMA5: // TODO: not sure
|
||||
case MBC_NONE:
|
||||
case MBC_BAD:
|
||||
@@ -736,30 +731,28 @@ static bool hasRAM(enum MbcType type)
|
||||
}
|
||||
|
||||
static const uint8_t ninLogo[] = {
|
||||
0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,
|
||||
0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
|
||||
0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E,
|
||||
0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
|
||||
0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC,
|
||||
0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E
|
||||
0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
|
||||
0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
|
||||
0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E,
|
||||
};
|
||||
|
||||
static const uint8_t trashLogo[] = {
|
||||
0xFF^0xCE, 0xFF^0xED, 0xFF^0x66, 0xFF^0x66, 0xFF^0xCC, 0xFF^0x0D, 0xFF^0x00, 0xFF^0x0B,
|
||||
0xFF^0x03, 0xFF^0x73, 0xFF^0x00, 0xFF^0x83, 0xFF^0x00, 0xFF^0x0C, 0xFF^0x00, 0xFF^0x0D,
|
||||
0xFF^0x00, 0xFF^0x08, 0xFF^0x11, 0xFF^0x1F, 0xFF^0x88, 0xFF^0x89, 0xFF^0x00, 0xFF^0x0E,
|
||||
0xFF^0xDC, 0xFF^0xCC, 0xFF^0x6E, 0xFF^0xE6, 0xFF^0xDD, 0xFF^0xDD, 0xFF^0xD9, 0xFF^0x99,
|
||||
0xFF^0xBB, 0xFF^0xBB, 0xFF^0x67, 0xFF^0x63, 0xFF^0x6E, 0xFF^0x0E, 0xFF^0xEC, 0xFF^0xCC,
|
||||
0xFF^0xDD, 0xFF^0xDC, 0xFF^0x99, 0xFF^0x9F, 0xFF^0xBB, 0xFF^0xB9, 0xFF^0x33, 0xFF^0x3E
|
||||
0xFF ^ 0xCE, 0xFF ^ 0xED, 0xFF ^ 0x66, 0xFF ^ 0x66, 0xFF ^ 0xCC, 0xFF ^ 0x0D, 0xFF ^ 0x00,
|
||||
0xFF ^ 0x0B, 0xFF ^ 0x03, 0xFF ^ 0x73, 0xFF ^ 0x00, 0xFF ^ 0x83, 0xFF ^ 0x00, 0xFF ^ 0x0C,
|
||||
0xFF ^ 0x00, 0xFF ^ 0x0D, 0xFF ^ 0x00, 0xFF ^ 0x08, 0xFF ^ 0x11, 0xFF ^ 0x1F, 0xFF ^ 0x88,
|
||||
0xFF ^ 0x89, 0xFF ^ 0x00, 0xFF ^ 0x0E, 0xFF ^ 0xDC, 0xFF ^ 0xCC, 0xFF ^ 0x6E, 0xFF ^ 0xE6,
|
||||
0xFF ^ 0xDD, 0xFF ^ 0xDD, 0xFF ^ 0xD9, 0xFF ^ 0x99, 0xFF ^ 0xBB, 0xFF ^ 0xBB, 0xFF ^ 0x67,
|
||||
0xFF ^ 0x63, 0xFF ^ 0x6E, 0xFF ^ 0x0E, 0xFF ^ 0xEC, 0xFF ^ 0xCC, 0xFF ^ 0xDD, 0xFF ^ 0xDC,
|
||||
0xFF ^ 0x99, 0xFF ^ 0x9F, 0xFF ^ 0xBB, 0xFF ^ 0xB9, 0xFF ^ 0x33, 0xFF ^ 0x3E,
|
||||
};
|
||||
|
||||
static enum { DMG, BOTH, CGB } model = DMG; // If DMG, byte is left alone
|
||||
#define FIX_LOGO 0x80
|
||||
#define TRASH_LOGO 0x40
|
||||
#define FIX_HEADER_SUM 0x20
|
||||
#define TRASH_HEADER_SUM 0x10
|
||||
#define FIX_GLOBAL_SUM 0x08
|
||||
#define TRASH_GLOBAL_SUM 0x04
|
||||
#define FIX_LOGO 0x80
|
||||
#define TRASH_LOGO 0x40
|
||||
#define FIX_HEADER_SUM 0x20
|
||||
#define TRASH_HEADER_SUM 0x10
|
||||
#define FIX_GLOBAL_SUM 0x08
|
||||
#define TRASH_GLOBAL_SUM 0x04
|
||||
static uint8_t fixSpec = 0;
|
||||
static const char *gameID = nullptr;
|
||||
static uint8_t gameIDLen;
|
||||
@@ -776,13 +769,11 @@ static bool sgb = false; // If false, SGB flags are left alone
|
||||
static const char *title = nullptr;
|
||||
static uint8_t titleLen;
|
||||
|
||||
static uint8_t maxTitleLen()
|
||||
{
|
||||
static uint8_t maxTitleLen() {
|
||||
return gameID ? 11 : model != DMG ? 15 : 16;
|
||||
}
|
||||
|
||||
static ssize_t readBytes(int fd, uint8_t *buf, size_t len)
|
||||
{
|
||||
static ssize_t readBytes(int fd, uint8_t *buf, size_t len) {
|
||||
// POSIX specifies that lengths greater than SSIZE_MAX yield implementation-defined results
|
||||
assert(len <= SSIZE_MAX);
|
||||
|
||||
@@ -807,8 +798,7 @@ static ssize_t readBytes(int fd, uint8_t *buf, size_t len)
|
||||
return total;
|
||||
}
|
||||
|
||||
static ssize_t writeBytes(int fd, uint8_t *buf, size_t len)
|
||||
{
|
||||
static ssize_t writeBytes(int fd, uint8_t *buf, size_t len) {
|
||||
// POSIX specifies that lengths greater than SSIZE_MAX yield implementation-defined results
|
||||
assert(len <= SSIZE_MAX);
|
||||
|
||||
@@ -838,8 +828,7 @@ static ssize_t writeBytes(int fd, uint8_t *buf, size_t len)
|
||||
* @param fixedByte The fixed byte at the address
|
||||
* @param areaName Name to be displayed in the warning message
|
||||
*/
|
||||
static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char const *areaName)
|
||||
{
|
||||
static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char const *areaName) {
|
||||
uint8_t origByte = rom0[addr];
|
||||
|
||||
if (!overwriteRom && origByte != 0 && origByte != fixedByte)
|
||||
@@ -855,16 +844,15 @@ static void overwriteByte(uint8_t *rom0, uint16_t addr, uint8_t fixedByte, char
|
||||
* @param size How many bytes to check
|
||||
* @param areaName Name to be displayed in the warning message
|
||||
*/
|
||||
static void overwriteBytes(uint8_t *rom0, uint16_t startAddr, uint8_t const *fixed, uint8_t size,
|
||||
char const *areaName)
|
||||
{
|
||||
static void overwriteBytes(
|
||||
uint8_t *rom0, uint16_t startAddr, uint8_t const *fixed, uint8_t size, char const *areaName
|
||||
) {
|
||||
if (!overwriteRom) {
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
uint8_t origByte = rom0[i + startAddr];
|
||||
|
||||
if (origByte != 0 && origByte != fixed[i]) {
|
||||
fprintf(stderr, "warning: Overwrote a non-zero byte in the %s\n",
|
||||
areaName);
|
||||
fprintf(stderr, "warning: Overwrote a non-zero byte in the %s\n", areaName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -879,8 +867,7 @@ static void overwriteBytes(uint8_t *rom0, uint16_t startAddr, uint8_t const *fix
|
||||
* @param name The file's name, to be displayed for error output
|
||||
* @param fileSize The file's size if known, 0 if not.
|
||||
*/
|
||||
static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
{
|
||||
static void processFile(int input, int output, char const *name, off_t fileSize) {
|
||||
// Both of these should be true for seekable files, and neither otherwise
|
||||
if (input == output)
|
||||
assert(fileSize != 0);
|
||||
@@ -896,8 +883,13 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
report("FATAL: Failed to read \"%s\"'s header: %s\n", name, strerror(errno));
|
||||
return;
|
||||
} else if (rom0Len < headerSize) {
|
||||
report("FATAL: \"%s\" too short, expected at least %jd ($%jx) bytes, got only %jd\n",
|
||||
name, (intmax_t)headerSize, (intmax_t)headerSize, (intmax_t)rom0Len);
|
||||
report(
|
||||
"FATAL: \"%s\" too short, expected at least %jd ($%jx) bytes, got only %jd\n",
|
||||
name,
|
||||
(intmax_t)headerSize,
|
||||
(intmax_t)headerSize,
|
||||
(intmax_t)rom0Len
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Accept partial reads if the file contains at least the header
|
||||
@@ -919,8 +911,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
overwriteByte(rom0, 0x143, model == BOTH ? 0x80 : 0xC0, "CGB flag");
|
||||
|
||||
if (newLicensee)
|
||||
overwriteBytes(rom0, 0x144, (uint8_t const *)newLicensee, newLicenseeLen,
|
||||
"new licensee code");
|
||||
overwriteBytes(
|
||||
rom0, 0x144, (uint8_t const *)newLicensee, newLicenseeLen, "new licensee code"
|
||||
);
|
||||
|
||||
if (sgb)
|
||||
overwriteByte(rom0, 0x146, 0x03, "SGB flag");
|
||||
@@ -963,9 +956,11 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
if (oldLicensee != UNSPECIFIED)
|
||||
overwriteByte(rom0, 0x14B, oldLicensee, "old licensee code");
|
||||
else if (sgb && rom0[0x14B] != 0x33)
|
||||
fprintf(stderr,
|
||||
"warning: SGB compatibility enabled, but old licensee was 0x%02x, not 0x33\n",
|
||||
rom0[0x14B]);
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: SGB compatibility enabled, but old licensee was 0x%02x, not 0x33\n",
|
||||
rom0[0x14B]
|
||||
);
|
||||
|
||||
if (romVersion != UNSPECIFIED)
|
||||
overwriteByte(rom0, 0x14C, romVersion, "mask ROM version number");
|
||||
@@ -981,9 +976,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
// 65536 banks = 1 GiB.
|
||||
// This should be reasonable for the time being, and may be extended later.
|
||||
std::vector<uint8_t> romx; // Buffer of ROMX bank data
|
||||
uint32_t nbBanks = 1; // Number of banks *targeted*, including ROM0
|
||||
size_t totalRomxLen = 0; // *Actual* size of ROMX data
|
||||
uint8_t bank[BANK_SIZE]; // Temp buffer used to store a whole bank's worth of data
|
||||
uint32_t nbBanks = 1; // Number of banks *targeted*, including ROM0
|
||||
size_t totalRomxLen = 0; // *Actual* size of ROMX data
|
||||
uint8_t bank[BANK_SIZE]; // Temp buffer used to store a whole bank's worth of data
|
||||
|
||||
// Handle ROMX
|
||||
if (input == output) {
|
||||
@@ -1006,7 +1001,9 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
// Update bank count, ONLY IF at least one byte was read
|
||||
if (bankLen) {
|
||||
// We're gonna read another bank, check that it won't be too much
|
||||
static_assert(0x10000 * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS");
|
||||
static_assert(
|
||||
0x10000 * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS"
|
||||
);
|
||||
if (nbBanks == 0x10000) {
|
||||
report("FATAL: \"%s\" has more than 65536 banks\n", name);
|
||||
return;
|
||||
@@ -1062,8 +1059,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
for (uint16_t i = 0x134; i < 0x14D; i++)
|
||||
sum -= rom0[i] + 1;
|
||||
|
||||
overwriteByte(rom0, 0x14D, fixSpec & TRASH_HEADER_SUM ? ~sum : sum,
|
||||
"header checksum");
|
||||
overwriteByte(rom0, 0x14D, fixSpec & TRASH_HEADER_SUM ? ~sum : sum, "header checksum");
|
||||
}
|
||||
|
||||
if (fixSpec & (FIX_GLOBAL_SUM | TRASH_GLOBAL_SUM)) {
|
||||
@@ -1113,8 +1109,12 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
report("FATAL: Failed to write \"%s\"'s ROM0: %s\n", name, strerror(errno));
|
||||
return;
|
||||
} else if (writeLen < rom0Len) {
|
||||
report("FATAL: Could only write %jd of \"%s\"'s %jd ROM0 bytes\n",
|
||||
(intmax_t)writeLen, name, (intmax_t)rom0Len);
|
||||
report(
|
||||
"FATAL: Could only write %jd of \"%s\"'s %jd ROM0 bytes\n",
|
||||
(intmax_t)writeLen,
|
||||
name,
|
||||
(intmax_t)rom0Len
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1127,8 +1127,12 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
report("FATAL: Failed to write \"%s\"'s ROMX: %s\n", name, strerror(errno));
|
||||
return;
|
||||
} else if ((size_t)writeLen < totalRomxLen) {
|
||||
report("FATAL: Could only write %jd of \"%s\"'s %zu ROMX bytes\n",
|
||||
(intmax_t)writeLen, name, totalRomxLen);
|
||||
report(
|
||||
"FATAL: Could only write %jd of \"%s\"'s %zu ROMX bytes\n",
|
||||
(intmax_t)writeLen,
|
||||
name,
|
||||
totalRomxLen
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1137,8 +1141,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
if (padValue != UNSPECIFIED) {
|
||||
if (input == output) {
|
||||
if (lseek(output, 0, SEEK_END) == (off_t)-1) {
|
||||
report("FATAL: Failed to seek to end of \"%s\": %s\n",
|
||||
name, strerror(errno));
|
||||
report("FATAL: Failed to seek to end of \"%s\": %s\n", name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1153,8 +1156,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
// The return value is either -1, or at most `thisLen`,
|
||||
// so it's fine to cast to `size_t`
|
||||
if ((size_t)ret != thisLen) {
|
||||
report("FATAL: Failed to write \"%s\"'s padding: %s\n",
|
||||
name, strerror(errno));
|
||||
report("FATAL: Failed to write \"%s\"'s padding: %s\n", name, strerror(errno));
|
||||
break;
|
||||
}
|
||||
len -= thisLen;
|
||||
@@ -1162,8 +1164,7 @@ static void processFile(int input, int output, char const *name, off_t fileSize)
|
||||
}
|
||||
}
|
||||
|
||||
static bool processFilename(char const *name)
|
||||
{
|
||||
static bool processFilename(char const *name) {
|
||||
nbErrors = 0;
|
||||
if (!strcmp(name, "-")) {
|
||||
(void)setmode(STDIN_FILENO, O_BINARY);
|
||||
@@ -1181,21 +1182,24 @@ static bool processFilename(char const *name)
|
||||
struct stat stat;
|
||||
|
||||
if (input == -1) {
|
||||
report("FATAL: Failed to open \"%s\" for reading+writing: %s\n",
|
||||
name, strerror(errno));
|
||||
report("FATAL: Failed to open \"%s\" for reading+writing: %s\n", name, strerror(errno));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (fstat(input, &stat) == -1) {
|
||||
report("FATAL: Failed to stat \"%s\": %s\n", name, strerror(errno));
|
||||
} else if (!S_ISREG(stat.st_mode)) { // TODO: Do we want to support other types?
|
||||
report("FATAL: \"%s\" is not a regular file, and thus cannot be modified in-place\n",
|
||||
name);
|
||||
report(
|
||||
"FATAL: \"%s\" is not a regular file, and thus cannot be modified in-place\n", name
|
||||
);
|
||||
} else if (stat.st_size < 0x150) {
|
||||
// This check is in theory redundant with the one in `processFile`, but it
|
||||
// prevents passing a file size of 0, which usually indicates pipes
|
||||
report("FATAL: \"%s\" too short, expected at least 336 ($150) bytes, got only %jd\n",
|
||||
name, (intmax_t)stat.st_size);
|
||||
report(
|
||||
"FATAL: \"%s\" too short, expected at least 336 ($150) bytes, got only %jd\n",
|
||||
name,
|
||||
(intmax_t)stat.st_size
|
||||
);
|
||||
} else {
|
||||
processFile(input, input, name, stat.st_size);
|
||||
}
|
||||
@@ -1204,48 +1208,53 @@ static bool processFilename(char const *name)
|
||||
}
|
||||
finish:
|
||||
if (nbErrors)
|
||||
fprintf(stderr, "Fixing \"%s\" failed with %u error%s\n",
|
||||
name, nbErrors, nbErrors == 1 ? "" : "s");
|
||||
fprintf(
|
||||
stderr,
|
||||
"Fixing \"%s\" failed with %u error%s\n",
|
||||
name,
|
||||
nbErrors,
|
||||
nbErrors == 1 ? "" : "s"
|
||||
);
|
||||
return nbErrors;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
nbErrors = 0;
|
||||
|
||||
for (int ch; (ch = musl_getopt_long_only(argc, argv, optstring, longopts, nullptr)) != -1;) {
|
||||
switch (ch) {
|
||||
size_t len;
|
||||
#define parseByte(output, name) \
|
||||
do { \
|
||||
char *endptr; \
|
||||
unsigned long tmp; \
|
||||
\
|
||||
if (musl_optarg[0] == 0) { \
|
||||
report("error: Argument to option '" name "' may not be empty\n"); \
|
||||
} else { \
|
||||
if (musl_optarg[0] == '$') { \
|
||||
tmp = strtoul(&musl_optarg[1], &endptr, 16); \
|
||||
do { \
|
||||
char *endptr; \
|
||||
unsigned long tmp; \
|
||||
\
|
||||
if (musl_optarg[0] == 0) { \
|
||||
report("error: Argument to option '" name "' may not be empty\n"); \
|
||||
} else { \
|
||||
tmp = strtoul(musl_optarg, &endptr, 0); \
|
||||
if (musl_optarg[0] == '$') { \
|
||||
tmp = strtoul(&musl_optarg[1], &endptr, 16); \
|
||||
} else { \
|
||||
tmp = strtoul(musl_optarg, &endptr, 0); \
|
||||
} \
|
||||
if (*endptr) \
|
||||
report( \
|
||||
"error: Expected number as argument to option '" name "', got %s\n", \
|
||||
musl_optarg \
|
||||
); \
|
||||
else if (tmp > 0xFF) \
|
||||
report("error: Argument to option '" name "' is larger than 255: %lu\n", tmp); \
|
||||
else \
|
||||
output = tmp; \
|
||||
} \
|
||||
if (*endptr) \
|
||||
report("error: Expected number as argument to option '" name "', got %s\n", \
|
||||
musl_optarg); \
|
||||
else if (tmp > 0xFF) \
|
||||
report("error: Argument to option '" name "' is larger than 255: %lu\n", tmp); \
|
||||
else \
|
||||
output = tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
} while (0)
|
||||
|
||||
case 'C':
|
||||
case 'c':
|
||||
model = ch == 'c' ? BOTH : CGB;
|
||||
if (titleLen > 15) {
|
||||
titleLen = 15;
|
||||
fprintf(stderr, "warning: Truncating title \"%s\" to 15 chars\n",
|
||||
title);
|
||||
fprintf(stderr, "warning: Truncating title \"%s\" to 15 chars\n", title);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1260,12 +1269,11 @@ do { \
|
||||
#define SPEC_g FIX_GLOBAL_SUM
|
||||
#define SPEC_G TRASH_GLOBAL_SUM
|
||||
#define overrideSpec(cur, bad) \
|
||||
do { \
|
||||
if (fixSpec & SPEC_##bad) \
|
||||
fprintf(stderr, \
|
||||
"warning: '" #cur "' overriding '" #bad "' in fix spec\n"); \
|
||||
fixSpec = (fixSpec & ~SPEC_##bad) | SPEC_##cur; \
|
||||
} while (0)
|
||||
do { \
|
||||
if (fixSpec & SPEC_##bad) \
|
||||
fprintf(stderr, "warning: '" #cur "' overriding '" #bad "' in fix spec\n"); \
|
||||
fixSpec = (fixSpec & ~SPEC_##bad) | SPEC_##cur; \
|
||||
} while (0)
|
||||
case 'l':
|
||||
overrideSpec(l, L);
|
||||
break;
|
||||
@@ -1288,8 +1296,7 @@ do { \
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "warning: Ignoring '%c' in fix spec\n",
|
||||
*musl_optarg);
|
||||
fprintf(stderr, "warning: Ignoring '%c' in fix spec\n", *musl_optarg);
|
||||
#undef overrideSpec
|
||||
}
|
||||
musl_optarg++;
|
||||
@@ -1301,14 +1308,12 @@ do { \
|
||||
len = strlen(gameID);
|
||||
if (len > 4) {
|
||||
len = 4;
|
||||
fprintf(stderr, "warning: Truncating game ID \"%s\" to 4 chars\n",
|
||||
gameID);
|
||||
fprintf(stderr, "warning: Truncating game ID \"%s\" to 4 chars\n", gameID);
|
||||
}
|
||||
gameIDLen = len;
|
||||
if (titleLen > 11) {
|
||||
titleLen = 11;
|
||||
fprintf(stderr, "warning: Truncating title \"%s\" to 11 chars\n",
|
||||
title);
|
||||
fprintf(stderr, "warning: Truncating title \"%s\" to 11 chars\n", title);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1321,9 +1326,9 @@ do { \
|
||||
len = strlen(newLicensee);
|
||||
if (len > 2) {
|
||||
len = 2;
|
||||
fprintf(stderr,
|
||||
"warning: Truncating new licensee \"%s\" to 2 chars\n",
|
||||
newLicensee);
|
||||
fprintf(
|
||||
stderr, "warning: Truncating new licensee \"%s\" to 2 chars\n", newLicensee
|
||||
);
|
||||
}
|
||||
newLicenseeLen = len;
|
||||
break;
|
||||
@@ -1335,18 +1340,22 @@ do { \
|
||||
case 'm':
|
||||
cartridgeType = parseMBC(musl_optarg);
|
||||
if (cartridgeType == MBC_BAD) {
|
||||
report("error: Unknown MBC \"%s\"\nAccepted MBC names:\n",
|
||||
musl_optarg);
|
||||
report("error: Unknown MBC \"%s\"\nAccepted MBC names:\n", musl_optarg);
|
||||
printAcceptedMBCNames();
|
||||
} else if (cartridgeType == MBC_WRONG_FEATURES) {
|
||||
report("error: Features incompatible with MBC (\"%s\")\nAccepted combinations:\n",
|
||||
musl_optarg);
|
||||
report(
|
||||
"error: Features incompatible with MBC (\"%s\")\nAccepted combinations:\n",
|
||||
musl_optarg
|
||||
);
|
||||
printAcceptedMBCNames();
|
||||
} else if (cartridgeType == MBC_BAD_RANGE) {
|
||||
report("error: Specified MBC ID out of range 0-255: %s\n",
|
||||
musl_optarg);
|
||||
report("error: Specified MBC ID out of range 0-255: %s\n", musl_optarg);
|
||||
} else if (cartridgeType == ROM_RAM || cartridgeType == ROM_RAM_BATTERY) {
|
||||
fprintf(stderr, "warning: ROM+RAM / ROM+RAM+BATTERY are under-specified and poorly supported\n");
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: ROM+RAM / ROM+RAM+BATTERY are under-specified and poorly "
|
||||
"supported\n"
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1377,8 +1386,7 @@ do { \
|
||||
|
||||
if (len > maxLen) {
|
||||
len = maxLen;
|
||||
fprintf(stderr, "warning: Truncating title \"%s\" to %u chars\n",
|
||||
title, maxLen);
|
||||
fprintf(stderr, "warning: Truncating title \"%s\" to %u chars\n", title, maxLen);
|
||||
}
|
||||
titleLen = len;
|
||||
break;
|
||||
@@ -1401,42 +1409,58 @@ do { \
|
||||
}
|
||||
|
||||
if ((cartridgeType & 0xFF00) == TPP1 && !japanese)
|
||||
fprintf(stderr, "warning: TPP1 overwrites region flag for its identification code, ignoring `-j`\n");
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: TPP1 overwrites region flag for its identification code, ignoring `-j`\n"
|
||||
);
|
||||
|
||||
// Check that RAM size is correct for "standard" mappers
|
||||
if (ramSize != UNSPECIFIED && (cartridgeType & 0xFF00) == 0) {
|
||||
if (cartridgeType == ROM_RAM || cartridgeType == ROM_RAM_BATTERY) {
|
||||
if (ramSize != 1)
|
||||
fprintf(stderr, "warning: MBC \"%s\" should have 2 KiB of RAM (-r 1)\n",
|
||||
mbcName(cartridgeType));
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: MBC \"%s\" should have 2 KiB of RAM (-r 1)\n",
|
||||
mbcName(cartridgeType)
|
||||
);
|
||||
} else if (hasRAM(cartridgeType)) {
|
||||
if (!ramSize) {
|
||||
fprintf(stderr,
|
||||
"warning: MBC \"%s\" has RAM, but RAM size was set to 0\n",
|
||||
mbcName(cartridgeType));
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: MBC \"%s\" has RAM, but RAM size was set to 0\n",
|
||||
mbcName(cartridgeType)
|
||||
);
|
||||
} else if (ramSize == 1) {
|
||||
fprintf(stderr,
|
||||
"warning: RAM size 1 (2 KiB) was specified for MBC \"%s\"\n",
|
||||
mbcName(cartridgeType));
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: RAM size 1 (2 KiB) was specified for MBC \"%s\"\n",
|
||||
mbcName(cartridgeType)
|
||||
);
|
||||
} // TODO: check possible values?
|
||||
} else if (ramSize) {
|
||||
fprintf(stderr,
|
||||
"warning: MBC \"%s\" has no RAM, but RAM size was set to %u\n",
|
||||
mbcName(cartridgeType), ramSize);
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: MBC \"%s\" has no RAM, but RAM size was set to %u\n",
|
||||
mbcName(cartridgeType),
|
||||
ramSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (sgb && oldLicensee != UNSPECIFIED && oldLicensee != 0x33)
|
||||
fprintf(stderr,
|
||||
"warning: SGB compatibility enabled, but old licensee is 0x%02x, not 0x33\n",
|
||||
oldLicensee);
|
||||
fprintf(
|
||||
stderr,
|
||||
"warning: SGB compatibility enabled, but old licensee is 0x%02x, not 0x33\n",
|
||||
oldLicensee
|
||||
);
|
||||
|
||||
argv += musl_optind;
|
||||
bool failed = nbErrors;
|
||||
|
||||
if (!*argv) {
|
||||
fputs("FATAL: Please specify an input file (pass `-` to read from standard input)\n",
|
||||
stderr);
|
||||
fputs(
|
||||
"FATAL: Please specify an input file (pass `-` to read from standard input)\n", stderr
|
||||
);
|
||||
printUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user