Last active
January 28, 2021 23:08
-
-
Save kode54/1b6eed5d864b0f3f8789d21e9183692f to your computer and use it in GitHub Desktop.
GSF to GBA ROM converter, requires my libpsflib.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <psflib/psflib.h> | |
void * source_fopen(const char * path) | |
{ | |
return fopen(path, "rb"); | |
} | |
size_t source_fread(void * buffer, size_t size, size_t count, void * handle) | |
{ | |
return fread(buffer, size, count, (FILE *)handle); | |
} | |
int source_fseek(void * handle, int64_t offset, int whence) | |
{ | |
return fseek((FILE *)handle, offset, whence); | |
} | |
int source_fclose(void * handle) | |
{ | |
fclose((FILE *)handle); | |
return 0; | |
} | |
long source_ftell(void * handle) | |
{ | |
return ftell((FILE *)handle); | |
} | |
static psf_file_callbacks source_callbacks = | |
{ | |
"/|\\", | |
source_fopen, | |
source_fread, | |
source_fseek, | |
source_fclose, | |
source_ftell | |
}; | |
unsigned get_be16( void const* p ) | |
{ | |
return (unsigned) ((unsigned char const*) p) [0] << 8 | | |
(unsigned) ((unsigned char const*) p) [1]; | |
} | |
unsigned get_le32( void const* p ) | |
{ | |
return (unsigned) ((unsigned char const*) p) [3] << 24 | | |
(unsigned) ((unsigned char const*) p) [2] << 16 | | |
(unsigned) ((unsigned char const*) p) [1] << 8 | | |
(unsigned) ((unsigned char const*) p) [0]; | |
} | |
unsigned get_be32( void const* p ) | |
{ | |
return (unsigned) ((unsigned char const*) p) [0] << 24 | | |
(unsigned) ((unsigned char const*) p) [1] << 16 | | |
(unsigned) ((unsigned char const*) p) [2] << 8 | | |
(unsigned) ((unsigned char const*) p) [3]; | |
} | |
void set_le32( void* p, unsigned n ) | |
{ | |
((unsigned char*) p) [0] = (unsigned char) n; | |
((unsigned char*) p) [1] = (unsigned char) (n >> 8); | |
((unsigned char*) p) [2] = (unsigned char) (n >> 16); | |
((unsigned char*) p) [3] = (unsigned char) (n >> 24); | |
} | |
struct gsf_loader_state | |
{ | |
int entry_set; | |
uint32_t entry; | |
uint8_t * data; | |
size_t data_size; | |
}; | |
static int gsf_loader(void * context, const uint8_t * exe, size_t exe_size, | |
const uint8_t * reserved, size_t reserved_size) | |
{ | |
if ( exe_size < 12 ) return -1; | |
struct gsf_loader_state * state = ( struct gsf_loader_state * ) context; | |
unsigned char *iptr; | |
size_t isize; | |
unsigned char *xptr; | |
unsigned xentry = get_le32(exe + 0); | |
unsigned xsize = get_le32(exe + 8); | |
unsigned xofs = get_le32(exe + 4) & 0x1ffffff; | |
if ( xsize < exe_size - 12 ) return -1; | |
if (!state->entry_set) | |
{ | |
state->entry = xentry; | |
state->entry_set = 1; | |
} | |
{ | |
iptr = state->data; | |
isize = state->data_size; | |
state->data = 0; | |
state->data_size = 0; | |
} | |
if (!iptr) | |
{ | |
size_t rsize = xofs + xsize; | |
{ | |
rsize -= 1; | |
rsize |= rsize >> 1; | |
rsize |= rsize >> 2; | |
rsize |= rsize >> 4; | |
rsize |= rsize >> 8; | |
rsize |= rsize >> 16; | |
rsize += 1; | |
} | |
iptr = (unsigned char *) malloc(rsize + 10); | |
if (!iptr) | |
return -1; | |
memset(iptr, 0, rsize + 10); | |
isize = rsize; | |
} | |
else if (isize < xofs + xsize) | |
{ | |
size_t rsize = xofs + xsize; | |
{ | |
rsize -= 1; | |
rsize |= rsize >> 1; | |
rsize |= rsize >> 2; | |
rsize |= rsize >> 4; | |
rsize |= rsize >> 8; | |
rsize |= rsize >> 16; | |
rsize += 1; | |
} | |
xptr = (unsigned char *) realloc(iptr, xofs + rsize + 10); | |
if (!xptr) | |
{ | |
free(iptr); | |
return -1; | |
} | |
iptr = xptr; | |
isize = rsize; | |
} | |
memcpy(iptr + xofs, exe + 12, xsize); | |
{ | |
state->data = iptr; | |
state->data_size = isize; | |
} | |
return 0; | |
} | |
static void print_message(void * context, const char * message) | |
{ | |
fputs(message, stderr); | |
fflush(stderr); | |
} | |
int main(int argc, char ** argv) | |
{ | |
int err; | |
char outname[512]; | |
char * ptr; | |
FILE * f; | |
struct gsf_loader_state state; | |
if (argc != 2) | |
{ | |
fprintf(stderr, "Usage:\tgsf2rom <filename.gsf>\n"); | |
return 1; | |
} | |
memset(&state, 0, sizeof(state)); | |
err = psf_load( argv[1], &source_callbacks, 0x22, gsf_loader, &state, 0, 0, 0, print_message, 0 ); | |
if (err <= 0) | |
{ | |
fprintf(stderr, "Invalid GSF file: %s\n", argv[1]); | |
return 1; | |
} | |
strcpy(outname, argv[1]); | |
ptr = strrchr(outname, '.'); | |
if (!ptr) ptr = outname + strlen(outname); | |
strcpy(ptr, ".gba"); | |
f = fopen(outname, "wb"); | |
if (!f) | |
{ | |
fprintf(stderr, "Unable to open output file: %s\n", outname); | |
return 1; | |
} | |
fwrite(state.data, 1, state.data_size, f); | |
fclose(f); | |
free(state.data); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment