Skip to content

Commit eea277a

Browse files
committed
Add more tests for RGBFIX
1 parent 538395b commit eea277a

34 files changed

+275
-88
lines changed

src/fix/fix.cpp

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -240,16 +240,17 @@ static void
240240
std::vector<uint8_t> romx; // Buffer of ROMX bank data
241241
uint32_t nbBanks = 1; // Number of banks *targeted*, including ROM0
242242
size_t totalRomxLen = 0; // *Actual* size of ROMX data
243-
uint8_t bank[BANK_SIZE]; // Temp buffer used to store a whole bank's worth of data
244243

245244
// Handle ROMX
245+
auto errorTooLarge = [&name]() {
246+
error("\"%s\" has more than 65536 banks", name); // LCOV_EXCL_LINE
247+
};
248+
static constexpr off_t NB_BANKS_LIMIT = 0x10000;
249+
static_assert(NB_BANKS_LIMIT * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS");
246250
if (input == output) {
247-
if (fileSize >= 0x10000 * BANK_SIZE) {
248-
error("\"%s\" has more than 65536 banks", name);
249-
return;
251+
if (fileSize >= NB_BANKS_LIMIT * BANK_SIZE) {
252+
return errorTooLarge(); // LCOV_EXCL_LINE
250253
}
251-
// This should be guaranteed from the size cap...
252-
static_assert(0x10000 * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS");
253254
// Compute number of banks and ROMX len from file size
254255
nbBanks = (fileSize + (BANK_SIZE - 1)) / BANK_SIZE; // ceil(fileSize / BANK_SIZE)
255256
totalRomxLen = fileSize >= BANK_SIZE ? fileSize - BANK_SIZE : 0;
@@ -258,19 +259,13 @@ static void
258259
for (;;) {
259260
romx.resize(nbBanks * BANK_SIZE);
260261
ssize_t bankLen = readBytes(input, &romx[(nbBanks - 1) * BANK_SIZE], BANK_SIZE);
261-
262262
// Update bank count, ONLY IF at least one byte was read
263263
if (bankLen) {
264264
// We're going to read another bank, check that it won't be too much
265-
static_assert(
266-
0x10000 * BANK_SIZE <= SSIZE_MAX, "Max input file size too large for OS"
267-
);
268-
if (nbBanks == 0x10000) {
269-
error("\"%s\" has more than 65536 banks", name);
270-
return;
265+
if (nbBanks == NB_BANKS_LIMIT) {
266+
return errorTooLarge(); // LCOV_EXCL_LINE
271267
}
272268
++nbBanks;
273-
274269
// Update global checksum, too
275270
for (uint16_t i = 0; i < bankLen; ++i) {
276271
globalSum += romx[totalRomxLen + i];
@@ -341,6 +336,7 @@ static void
341336
// Pipes have already read ROMX and updated globalSum, but not regular files
342337
if (input == output) {
343338
for (;;) {
339+
uint8_t bank[BANK_SIZE];
344340
ssize_t bankLen = readBytes(input, bank, sizeof(bank));
345341

346342
for (uint16_t i = 0; i < bankLen; ++i) {
@@ -432,8 +428,9 @@ static void
432428
// LCOV_EXCL_STOP
433429
}
434430
}
431+
uint8_t bank[BANK_SIZE];
435432
memset(bank, options.padValue, sizeof(bank));
436-
size_t len = (nbBanks - 1) * BANK_SIZE - totalRomxLen; // Don't count ROM0!
433+
size_t len = (nbBanks - 1) * sizeof(bank) - totalRomxLen; // Don't count ROM0!
437434

438435
while (len) {
439436
static_assert(sizeof(bank) <= SSIZE_MAX, "Bank too large for reading");
@@ -470,8 +467,10 @@ bool fix_ProcessFile(char const *name, char const *outputName) {
470467
} else {
471468
output = open(outputName, O_WRONLY | O_BINARY | O_CREAT, 0600);
472469
if (output == -1) {
470+
// LCOV_EXCL_START
473471
error("Failed to open \"%s\" for writing: %s", outputName, strerror(errno));
474472
return true;
473+
// LCOV_EXCL_STOP
475474
}
476475
openedOutput = true;
477476
}

src/fix/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ static void initLogo() {
122122
logoFile = stdin;
123123
}
124124
if (!logoFile) {
125+
// LCOV_EXCL_START
125126
fatal("Failed to open \"%s\" for reading: %s", options.logoFilename, strerror(errno));
127+
// LCOV_EXCL_STOP
126128
}
127129
Defer closeLogo{[&] { fclose(logoFile); }};
128130

src/fix/mbc.cpp

Lines changed: 29 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ bool mbc_HasRAM(MbcType type) {
9898
return search != mbcData.end() && search->second.second;
9999
}
100100

101-
static void skipBlankSpace(char const *&ptr) {
102-
ptr += strspn(ptr, " \t");
103-
}
104-
105101
static void skipMBCSpace(char const *&ptr) {
106102
ptr += strspn(ptr, " \t_");
107103
}
@@ -115,16 +111,6 @@ static char normalizeMBCChar(char c) {
115111
return c;
116112
}
117113

118-
static bool readMBCSlice(char const *&name, char const *expected) {
119-
while (*expected) {
120-
// If `name` is too short, the character will be '\0' and this will return `false`
121-
if (normalizeMBCChar(*name++) != *expected++) {
122-
return false;
123-
}
124-
}
125-
return true;
126-
}
127-
128114
[[noreturn]]
129115
static void fatalUnknownMBC(char const *name) {
130116
fatal("Unknown MBC \"%s\"\n%s", name, acceptedMBCNames);
@@ -136,8 +122,7 @@ static void fatalWrongMBCFeatures(char const *name) {
136122
}
137123

138124
MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor) {
139-
char const *ptr = name;
140-
skipBlankSpace(ptr); // Trim off leading blank space
125+
char const *ptr = name + strspn(name, " \t"); // Skip leading blank space
141126

142127
if (!strcasecmp(ptr, "help") || !strcasecmp(ptr, "list")) {
143128
puts(acceptedMBCNames); // Outputs to stdout and appends a newline
@@ -156,14 +141,16 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
156141
}
157142

158143
// Begin by reading the MBC type:
159-
uint16_t mbc;
144+
uint16_t mbc = UINT16_MAX;
160145

161-
#define tryReadSlice(expected) \
162-
do { \
163-
if (!readMBCSlice(ptr, expected)) { \
164-
fatalUnknownMBC(name); \
165-
} \
166-
} while (0)
146+
auto tryReadSlice = [&ptr, &name](char const *expected) {
147+
while (*expected) {
148+
// If `name` is too short, the character will be '\0' and this will return `false`
149+
if (normalizeMBCChar(*ptr++) != *expected++) {
150+
fatalUnknownMBC(name);
151+
}
152+
}
153+
};
167154

168155
switch (*ptr++) {
169156
case 'R': // ROM / ROM_ONLY
@@ -183,13 +170,7 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
183170
switch (*ptr++) {
184171
case 'B':
185172
case 'b':
186-
switch (*ptr++) {
187-
case 'C':
188-
case 'c':
189-
break;
190-
default:
191-
fatalUnknownMBC(name);
192-
}
173+
tryReadSlice("C");
193174
switch (*ptr++) {
194175
case '1':
195176
mbc = MBC1;
@@ -209,17 +190,13 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
209190
case '7':
210191
mbc = MBC7_SENSOR_RUMBLE_RAM_BATTERY;
211192
break;
212-
default:
213-
fatalUnknownMBC(name);
214193
}
215194
break;
216195
case 'M':
217196
case 'm':
218197
tryReadSlice("M01");
219198
mbc = MMM01;
220199
break;
221-
default:
222-
fatalUnknownMBC(name);
223200
}
224201
break;
225202

@@ -242,7 +219,7 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
242219
tryReadSlice("MA5");
243220
mbc = BANDAI_TAMA5;
244221
break;
245-
case 'P': {
222+
case 'P':
246223
tryReadSlice("P1");
247224
// Parse version
248225
skipMBCSpace(ptr);
@@ -266,9 +243,6 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
266243
mbc = TPP1;
267244
break;
268245
}
269-
default:
270-
fatalUnknownMBC(name);
271-
}
272246
break;
273247

274248
case 'H': // HuC{1, 3}
@@ -281,12 +255,11 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
281255
case '3':
282256
mbc = HUC3;
283257
break;
284-
default:
285-
fatalUnknownMBC(name);
286258
}
287259
break;
260+
}
288261

289-
default:
262+
if (mbc == UINT16_MAX) {
290263
fatalUnknownMBC(name);
291264
}
292265

@@ -301,18 +274,10 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
301274
static constexpr uint8_t MULTIRUMBLE = 1 << 2;
302275
// clang-format on
303276

304-
for (;;) {
305-
skipBlankSpace(ptr); // Trim off trailing blank space
306-
307-
// If done, start processing "features"
308-
if (!*ptr) {
309-
break;
310-
}
277+
while (*ptr) {
311278
// We expect a '+' at this point
312279
skipMBCSpace(ptr);
313-
if (*ptr++ != '+') {
314-
fatalUnknownMBC(name);
315-
}
280+
tryReadSlice("+");
316281
skipMBCSpace(ptr);
317282

318283
switch (*ptr++) {
@@ -341,8 +306,6 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
341306
tryReadSlice("M");
342307
features |= RAM;
343308
break;
344-
default:
345-
fatalUnknownMBC(name);
346309
}
347310
break;
348311

@@ -357,12 +320,8 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
357320
tryReadSlice("IMER");
358321
features |= TIMER;
359322
break;
360-
361-
default:
362-
fatalUnknownMBC(name);
363323
}
364324
}
365-
#undef tryReadSlice
366325

367326
switch (mbc) {
368327
case ROM:
@@ -459,37 +418,34 @@ MbcType mbc_ParseName(char const *name, uint8_t &tpp1Major, uint8_t &tpp1Minor)
459418
}
460419
break;
461420

462-
case TPP1:
421+
case TPP1: {
422+
// clang-format off: vertically align values
423+
static constexpr uint8_t BATTERY_TPP1 = 1 << 3;
424+
static constexpr uint8_t TIMER_TPP1 = 1 << 2;
425+
static constexpr uint8_t MULTIRUMBLE_TPP1 = 1 << 1;
426+
static constexpr uint8_t RUMBLE_TPP1 = 1 << 0;
427+
// clang-format on
428+
463429
if (features & RAM) {
464430
warning(WARNING_MBC, "TPP1 requests RAM implicitly if given a non-zero RAM size");
465431
}
466432
if (features & BATTERY) {
467-
mbc |= 0x08;
433+
mbc |= BATTERY_TPP1;
468434
}
469435
if (features & TIMER) {
470-
mbc |= 0x04;
471-
}
472-
if (features & MULTIRUMBLE) {
473-
mbc |= 0x03; // Also set the rumble flag
436+
mbc |= TIMER_TPP1;
474437
}
475438
if (features & RUMBLE) {
476-
mbc |= 0x01;
439+
mbc |= RUMBLE_TPP1;
477440
}
478441
if (features & SENSOR) {
479442
fatalWrongMBCFeatures(name);
480443
}
481-
// Multiple rumble speeds imply rumble
482-
if (mbc & 0x01) {
483-
assume(mbc & 0x02);
444+
if (features & MULTIRUMBLE) {
445+
mbc |= MULTIRUMBLE_TPP1 | RUMBLE_TPP1; // Multiple rumble speeds imply rumble
484446
}
485447
break;
486448
}
487-
488-
skipBlankSpace(ptr); // Trim off trailing blank space
489-
490-
// If there is still something left, error out
491-
if (*ptr) {
492-
fatalUnknownMBC(name);
493449
}
494450

495451
return static_cast<MbcType>(mbc);

test/fix/bad-huc1-features.err

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FATAL: Features incompatible with MBC ("HUC1")
2+
Accepted MBC names:
3+
ROM ($00) [aka ROM_ONLY]
4+
MBC1 ($01), MBC1+RAM ($02), MBC1+RAM+BATTERY ($03)
5+
MBC2 ($05), MBC2+BATTERY ($06)
6+
ROM+RAM ($08) [deprecated], ROM+RAM+BATTERY ($09) [deprecated]
7+
MMM01 ($0B), MMM01+RAM ($0C), MMM01+RAM+BATTERY ($0D)
8+
MBC3+TIMER+BATTERY ($0F), MBC3+TIMER+RAM+BATTERY ($10)
9+
MBC3 ($11), MBC3+RAM ($12), MBC3+RAM+BATTERY ($13)
10+
MBC5 ($19), MBC5+RAM ($1A), MBC5+RAM+BATTERY ($1B)
11+
MBC5+RUMBLE ($1C), MBC5+RUMBLE+RAM ($1D), MBC5+RUMBLE+RAM+BATTERY ($1E)
12+
MBC6 ($20)
13+
MBC7+SENSOR+RUMBLE+RAM+BATTERY ($22)
14+
POCKET_CAMERA ($FC)
15+
BANDAI_TAMA5 ($FD) [aka TAMA5]
16+
HUC3 ($FE)
17+
HUC1+RAM+BATTERY ($FF)
18+
19+
TPP1_1.0, TPP1_1.0+RUMBLE, TPP1_1.0+MULTIRUMBLE, TPP1_1.0+TIMER,
20+
TPP1_1.0+TIMER+RUMBLE, TPP1_1.0+TIMER+MULTIRUMBLE, TPP1_1.0+BATTERY,
21+
TPP1_1.0+BATTERY+RUMBLE, TPP1_1.0+BATTERY+MULTIRUMBLE,
22+
TPP1_1.0+BATTERY+TIMER, TPP1_1.0+BATTERY+TIMER+RUMBLE,
23+
TPP1_1.0+BATTERY+TIMER+MULTIRUMBLE

test/fix/bad-huc1-features.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-m HUC1

test/fix/bad-mbc-name.err

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FATAL: Unknown MBC "MBC9"
2+
Accepted MBC names:
3+
ROM ($00) [aka ROM_ONLY]
4+
MBC1 ($01), MBC1+RAM ($02), MBC1+RAM+BATTERY ($03)
5+
MBC2 ($05), MBC2+BATTERY ($06)
6+
ROM+RAM ($08) [deprecated], ROM+RAM+BATTERY ($09) [deprecated]
7+
MMM01 ($0B), MMM01+RAM ($0C), MMM01+RAM+BATTERY ($0D)
8+
MBC3+TIMER+BATTERY ($0F), MBC3+TIMER+RAM+BATTERY ($10)
9+
MBC3 ($11), MBC3+RAM ($12), MBC3+RAM+BATTERY ($13)
10+
MBC5 ($19), MBC5+RAM ($1A), MBC5+RAM+BATTERY ($1B)
11+
MBC5+RUMBLE ($1C), MBC5+RUMBLE+RAM ($1D), MBC5+RUMBLE+RAM+BATTERY ($1E)
12+
MBC6 ($20)
13+
MBC7+SENSOR+RUMBLE+RAM+BATTERY ($22)
14+
POCKET_CAMERA ($FC)
15+
BANDAI_TAMA5 ($FD) [aka TAMA5]
16+
HUC3 ($FE)
17+
HUC1+RAM+BATTERY ($FF)
18+
19+
TPP1_1.0, TPP1_1.0+RUMBLE, TPP1_1.0+MULTIRUMBLE, TPP1_1.0+TIMER,
20+
TPP1_1.0+TIMER+RUMBLE, TPP1_1.0+TIMER+MULTIRUMBLE, TPP1_1.0+BATTERY,
21+
TPP1_1.0+BATTERY+RUMBLE, TPP1_1.0+BATTERY+MULTIRUMBLE,
22+
TPP1_1.0+BATTERY+TIMER, TPP1_1.0+BATTERY+TIMER+RUMBLE,
23+
TPP1_1.0+BATTERY+TIMER+MULTIRUMBLE

test/fix/bad-mbc-name.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-m MBC9

test/fix/bad-mbc-parse.err

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FATAL: Unknown MBC "123abc"
2+
Accepted MBC names:
3+
ROM ($00) [aka ROM_ONLY]
4+
MBC1 ($01), MBC1+RAM ($02), MBC1+RAM+BATTERY ($03)
5+
MBC2 ($05), MBC2+BATTERY ($06)
6+
ROM+RAM ($08) [deprecated], ROM+RAM+BATTERY ($09) [deprecated]
7+
MMM01 ($0B), MMM01+RAM ($0C), MMM01+RAM+BATTERY ($0D)
8+
MBC3+TIMER+BATTERY ($0F), MBC3+TIMER+RAM+BATTERY ($10)
9+
MBC3 ($11), MBC3+RAM ($12), MBC3+RAM+BATTERY ($13)
10+
MBC5 ($19), MBC5+RAM ($1A), MBC5+RAM+BATTERY ($1B)
11+
MBC5+RUMBLE ($1C), MBC5+RUMBLE+RAM ($1D), MBC5+RUMBLE+RAM+BATTERY ($1E)
12+
MBC6 ($20)
13+
MBC7+SENSOR+RUMBLE+RAM+BATTERY ($22)
14+
POCKET_CAMERA ($FC)
15+
BANDAI_TAMA5 ($FD) [aka TAMA5]
16+
HUC3 ($FE)
17+
HUC1+RAM+BATTERY ($FF)
18+
19+
TPP1_1.0, TPP1_1.0+RUMBLE, TPP1_1.0+MULTIRUMBLE, TPP1_1.0+TIMER,
20+
TPP1_1.0+TIMER+RUMBLE, TPP1_1.0+TIMER+MULTIRUMBLE, TPP1_1.0+BATTERY,
21+
TPP1_1.0+BATTERY+RUMBLE, TPP1_1.0+BATTERY+MULTIRUMBLE,
22+
TPP1_1.0+BATTERY+TIMER, TPP1_1.0+BATTERY+TIMER+RUMBLE,
23+
TPP1_1.0+BATTERY+TIMER+MULTIRUMBLE

test/fix/bad-mbc-parse.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-m 123abc

test/fix/bad-mbc-range.err

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FATAL: Specified MBC ID out of range 0-255: "999"

0 commit comments

Comments
 (0)