Skip to content

Instantly share code, notes, and snippets.

@profi200
Last active March 30, 2023 20:23
Show Gist options
  • Save profi200/e06794d7561ed552c518b4b0b2f5f2f6 to your computer and use it in GitHub Desktop.
Save profi200/e06794d7561ed552c518b4b0b2f5f2f6 to your computer and use it in GitHub Desktop.
A tool to fix wrong byte order GBA EEPROM saves as created by some emulators.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// Compile with "gcc -std=c17 -O2 -fstrict-aliasing -ffunction-sections -Wall -Wl,--gc-sections gbaEepromSaveFix.c -o gbaEepromSaveFix"
int main(int argc, char *argv[])
{
int res = 0;
FILE *f = fopen(argv[1], "rb+");
if(f != NULL)
{
do
{
fseek(f, 0, SEEK_END);
const size_t fSize = ftell(f);
// Minimum 32 because of the unrolled byteswap loop below.
// The last check is a power of 2 check.
if(fSize == 0 || fSize < 32 || (fSize & (fSize - 1)) != 0)
{
fputs("Broken save file or incorrect size!\n", stderr);
res = 2;
break;
}
fseek(f, 0, SEEK_SET);
uint64_t *buf = (uint64_t*)malloc(fSize);
if(buf == NULL)
{
fputs("Out of memory.\n", stderr);
res = 3;
break;
}
if(fread(buf, 1, fSize, f) != fSize)
{
fputs("Failed to read file.\n", stderr);
res = 4;
free(buf);
break;
}
for(size_t i = 0; i < fSize / 8; i += 4)
{
buf[i + 0] = __builtin_bswap64(buf[i + 0]);
buf[i + 1] = __builtin_bswap64(buf[i + 1]);
buf[i + 2] = __builtin_bswap64(buf[i + 2]);
buf[i + 3] = __builtin_bswap64(buf[i + 3]);
}
fseek(f, 0, SEEK_SET);
if(fwrite(buf, 1, fSize, f) != fSize)
{
fputs("Failed to write to file.\n", stderr);
res = 5;
}
free(buf);
} while(0);
fclose(f);
}
else
{
fputs("Failed to open save file.\n", stderr);
res = 1;
}
if(res == 0) puts("Done.");
return res;
}
@ihaveamac
Copy link

To compile on macOS: clang -std=c17 -O2 -fstrict-aliasing -ffunction-sections -Wall gbaEepromSaveFix.c -o gbaEepromSaveFix (the -Wl,--gc-sections part is removed)

@profi200
Copy link
Author

Ah, thanks. Didn't know this is broken on OSX.

@FoxBlocks
Copy link

FoxBlocks commented Sep 2, 2022

This doesn't work for me on Kirby & The Amazing Mirror. I tried using this to convert from open_agb_firm to emulator, and all save slots in the save file appear as 0% complete. Is there something I'm missing? I ran this on Windows 11 via WSL, compiled with the supplied gcc command.

@FoxBlocks
Copy link

FoxBlocks commented Sep 2, 2022

Hmm, weird. I tried importing the save file from open_agb_firm directly into VisualBoyAdvance, and after giving me a "Cannot open file" error, it actually read it and converted the save. Not sure how that worked, but it did. I transfered that new save to Lemuroid and it worked there too. Again, very strange.

I'll just use that to transfer my save to and from open_agb_firm for now.

@profi200
Copy link
Author

profi200 commented Sep 2, 2022

Is it even an EEPROM save? They usually have a size of either 512 bytes or 8 KiB.

@FoxBlocks
Copy link

It's 32KB.

@profi200
Copy link
Author

profi200 commented Sep 3, 2022

Then it's a SRAM save and doesn't need conversion.

@FoxBlocks
Copy link

Oh, okay. That explains it. I'm sorry for wasting your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment