Skip to content

Commit

Permalink
Rewrite calculateChecksum(), add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Optiroc committed Mar 16, 2024
1 parent c97ce65 commit 5017dc7
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 79 deletions.
24 changes: 13 additions & 11 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/superfamicheck",
"args": ["test/data/public/rom1.sfc"],
"preLaunchTask": "${defaultBuildTask}"
}
]
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/superfamicheck",
"args": [
"test/data/public/rom1.sfc"
],
"preLaunchTask": "${defaultBuildTask}",
}
]
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ superfamicheck is programmed by David Lindecrantz and distributed under the term


## building
in a unix-like environment simply `make` the binary. on windows use cmake to generate a build environment.
use cmake to generate a build environment, or simply type `make` which will run cmake for you.

## operation

Expand Down
70 changes: 35 additions & 35 deletions src/sfcRom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,16 @@ sfcRom::sfcRom(const string& path) {
{
if ((mode & 0xe0) != 0x20) {
correctedMode = headerLocation >= 0x8000 ? 0x21 : 0x20;
hasLegalMode = false;
hasSevereIssues = true;
++issues;
} else {
hasLegalMode = true;
}

if (mapperName.empty()) {
hasKnownMapper = false;
++issues;
} else {
hasKnownMapper = true;
}
}

Expand All @@ -124,17 +126,20 @@ sfcRom::sfcRom(const string& path) {
// Check RAM size
{
if ((hasRam && ramSize > 0x0f) || (!hasRam && ramSize != 0)) {
hasCorrectRamSize = false;
++issues;
} else {
hasCorrectRamSize = true;
}
}

// Calculate checksum
{
correctedChecksum = calculateChecksum();
correctedComplement = ~correctedChecksum;
if (checksum != correctedChecksum) {
if ((checksum != correctedChecksum) || complement != correctedComplement) {
++issues;
} else {
hasCorrectChecksum = true;
}
}

Expand Down Expand Up @@ -246,7 +251,7 @@ string sfcRom::description(bool silent) const {
os << " RAM size should be 0x00" << '\n';
}
}
if (checksum != correctedChecksum || complement != correctedComplement) {
if (!hasCorrectChecksum) {
os << " Checksum/complement should be 0x" << setw(4) << correctedChecksum << "/0x" << setw(4) << correctedComplement
<< '\n';
}
Expand Down Expand Up @@ -621,58 +626,53 @@ void sfcRom::getHeaderInfo(const vector<uint8_t>& header) {
}

uint16_t sfcRom::calculateChecksum() const {
size_t imageSize = image.size();
size_t mappedSize;
vector<uint8_t> img = image;
putWord(img, headerLocation + 0x2c, 0xffff);
putWord(img, headerLocation + 0x2e, 0x0000);

// Base and mask for out of bounds mirroring
uint32_t base = 0;
uint32_t offsetMask = 0xffffffff;
uint32_t offsetMod = 0xffffffff;
size_t imageSize = img.size();
size_t mappedSize;

if (mapper == 0x0a && chipset == 0xf9 && chipsetSubtype == 0x00) {
// Extended HiROM/SPC7110+RTC+Battery
mappedSize = imageSize;
} else if (mapper == 0x0a && chipset == 0xf5 && chipsetSubtype == 0x00) {
// Extended HiROM/SPC7110+Battery
mappedSize = imageSize > 0x200000 ? imageSize << 1 : imageSize;
offsetMod = imageSize;
while (mappedSize > img.size()) {
size_t remaining = mappedSize - img.size();
if (remaining > image.size()) {
remaining = image.size();
}
if ((remaining + img.size()) > mappedSize) {
remaining = mappedSize - img.size();
}
vector<uint8_t> mirror(img.begin(), img.begin() + remaining);
img.insert(img.end(), mirror.begin(), mirror.end());
}
} else {
// Standard mapping
mappedSize = 1 << (correctedRomSize != 0 ? correctedRomSize + 10 : romSize + 10);
uint32_t mask = 1;
uint32_t t = imageSize;
while (t >>= 1) {
mask <<= 1;
mask += 1;
while (mappedSize > img.size()) {
vector<uint8_t> mirror(img.begin() + (mappedSize >> 1), img.end());
img.insert(img.end(), mirror.begin(), mirror.end());
}
mask >>= 1;
base = mask + 1;
offsetMask = imageSize - base - 1;
}

// Add sum
auto img = image;
putWord(img, headerLocation + 0x2c, 0xffff);
putWord(img, headerLocation + 0x2e, 0x0000);
uint16_t sum = 0;

for (size_t offset = 0; offset < mappedSize; ++offset) {
size_t imgOffset = offset % offsetMod;
if (imgOffset < imageSize) {
sum += img[imgOffset];
} else {
size_t mirrorOffset = base + (imgOffset & offsetMask);
sum += img[mirrorOffset];
}
size_t length = img.size();
for (size_t offset = 0; offset < length; ++offset) {
sum += img[offset];
}
return sum;
}


// Get/put little endian word
// Get little endian word
uint16_t getWord(const vector<uint8_t>& vec, size_t offset) {
return (uint16_t)((vec[offset]) + ((uint8_t)(vec[offset + 1]) << 8));
}

// Put little endian word
void putWord(vector<uint8_t>& vec, size_t offset, uint16_t value) {
vec[offset] = (uint8_t)(value & 0xff);
vec[offset + 1] = (uint8_t)(value >> 8);
Expand Down
43 changes: 22 additions & 21 deletions src/sfcRom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ struct sfcRom {

bool hasCopierHeader = false;
bool hasCorrectTitle = false;
bool hasCorrectRamSize = true;
bool hasLegalMode = true;
bool hasKnownMapper = true;
bool hasCorrectRamSize = false;
bool hasCorrectChecksum = false;
bool hasLegalMode = false;
bool hasKnownMapper = false;
bool hasNewFormatHeader = false;

std::string title;
Expand All @@ -29,19 +30,28 @@ struct sfcRom {
std::string version;
std::string country;

uint8_t mode;
uint8_t mapper;
bool fast;
uint8_t mode = 0;
uint8_t mapper = 0;
bool fast = false;
bool hasRam = false;

uint8_t chipset;
uint8_t chipset = 0;
uint8_t chipsetSubtype = 0;
uint8_t romSize;
uint8_t ramSize;
uint8_t countryCode;
uint8_t romSize = 0;
uint8_t ramSize = 0;
uint8_t countryCode = 0;

uint16_t checksum;
uint16_t complement;
uint16_t checksum = 0;
uint16_t complement = 0;

size_t imageSize = 0;
size_t imageOffset = 0;
size_t headerLocation = 0;

uint8_t correctedMode = 0;
uint8_t correctedRomSize = 0;
uint16_t correctedChecksum = 0;
uint16_t correctedComplement = 0;

private:
std::string filepath;
Expand All @@ -50,13 +60,4 @@ struct sfcRom {
void getHeaderInfo(const std::vector<uint8_t>& header);
int scoreHeaderLocation(size_t location) const;
uint16_t calculateChecksum() const;

size_t imageSize;
size_t imageOffset = 0;
size_t headerLocation = 0;

uint8_t correctedMode = 0;
uint8_t correctedRomSize = 0;
uint16_t correctedChecksum;
uint16_t correctedComplement;
};
Loading

0 comments on commit 5017dc7

Please sign in to comment.