addrom

Simple tool for adding a rom entry to a Pandora's Box 3 list.dat
Log | Files | Refs | LICENSE

commit 682cab4976ad367d532c5d47e73bab73ade40024
Author: Quentin Rameau <quinq@fifth.space>
Date:   Mon,  9 Nov 2015 09:46:55 +0100

Initial commit

Diffstat:
Makefile | 38++++++++++++++++++++++++++++++++++++++
addrom.c | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
arg.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
config.mk | 14++++++++++++++
4 files changed, 320 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,38 @@ +include config.mk + +SRC = addrom.c +OBJ = ${SRC:.c=.o} + +all: options addrom + +options: + @echo addrom build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +addrom: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f addrom ${OBJ} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f addrom ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/addrom + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/addrom + +.PHONY: all options clean install uninstall diff --git a/addrom.c b/addrom.c @@ -0,0 +1,205 @@ +#include <sys/types.h> +#include <sys/stat.h> + +#include <fcntl.h> +#include <inttypes.h> +#include <libgen.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "arg.h" + +#define HEADERSZSZ 4 +#define GAMECNTSZ 4 +#define HEADERSZ 16 +#define CHTITLESZ 64 +#define ENTITLESZ 32 +#define ROMNAMESZ 16 +#define MAGICSZ 8 +#define ENTRYSZ (CHTITLESZ + ENTITLESZ + ROMNAMESZ + MAGICSZ) + +#define MAGIC 0x0000000000000000 + +typedef struct { + char *chtitle; + char *entitle; + char *romname; +} Rom; + +char *argv0; +static char *in, *out; +static intmax_t place; + +static void +die(const char *errstr, ...) +{ + va_list ap; + + va_start(ap, errstr); + vfprintf(stderr, errstr, ap); + va_end(ap); + + exit(1); +} + +static void +addrom(char *datfile, const Rom *rom) +{ + ssize_t pos = 0; + + if (rom->chtitle) + strncpy(datfile + pos, rom->chtitle, CHTITLESZ); + pos += CHTITLESZ; + if (rom->entitle) + strncpy(datfile + pos, rom->entitle, ENTITLESZ); + pos += ENTITLESZ; + if (rom->romname) + strncpy(datfile + pos, rom->romname, ROMNAMESZ); + pos += ROMNAMESZ; + *(uint64_t *)(datfile + pos) = MAGIC; +} + +/* not used +static uint64_t +getgamecount(int n) +{ + return (n * 0x88888889) >> 32 >> 6; +} +*/ + +static uint32_t +setgamecount(uint64_t n) +{ + return (n << 32 << 6) / 0x88888888; +} + +static void +ereadinfile(char *datbuf, const ssize_t size, FILE *infile) +{ + if (fread(datbuf, 1, size, infile) != size) + die("Couldn't read %zu bytes of input file %s\n", size, in); +} + +static void +usage(void) +{ + die("usage: %s [-c chinesetitle] [-e englishtitle] -i inputlist " + "[-n placeinlist] -o outputlist -r romname\n", basename(argv0)); +} + +int +main(int argc, char *argv[]) +{ + struct stat st; + Rom rom = { 0 }; + off_t infilesize; + size_t outbufsize; + ssize_t offset; + FILE *infile, *outfile; + char *outbuf; + int infd; + + ARGBEGIN { + case 'c': + rom.chtitle = EARGF(usage()); + if (strlen(rom.chtitle) > CHTITLESZ) + die("Chinese title must be less then than %zu bytes\n", + CHTITLESZ); + break; + case 'e': + rom.entitle = EARGF(usage()); + if (strlen(rom.entitle) > ENTITLESZ) + die("English title must be less then than %zu bytes\n", + ENTITLESZ); + break; + case 'i': + in = EARGF(usage()); + break; + case 'n': + place = strtoimax(EARGF(usage()), NULL, 10); + if (place < 1) + die("Place must be superior to 0\n"); + break; + case 'o': + out = EARGF(usage()); + break; + case 'r': + rom.romname = EARGF(usage()); + if (strlen(rom.romname) > ROMNAMESZ) + die("Rom name must be less then than %zu bytes\n", + ROMNAMESZ); + break; + default: + usage(); + break; + } ARGEND + + if (!in || !out || !rom.romname) + usage(); + + if (access(out, F_OK) != -1) + die("Output file %s exists and will not be overwritten\n", + out); + + if ((infd = open(in, O_RDONLY)) == -1) + die("Can't open input file %s\n", in); + + if (fstat(infd, &st) == -1 || !S_ISREG(st.st_mode)) + die("File %s is not a regular file\n", in); + + if ((infilesize = st.st_size) < HEADERSZ) + die("Corrupted input file %s\n", in); + + if (!(infile = fdopen(infd, "r"))) + die("Can't open input file %s\n", in); + + outbufsize = infilesize + ENTRYSZ; + + if (!(outbuf = calloc(outbufsize, 1))) + die("Can't allocate enough memory for reading input file\n"); +/* + if (place * ENTRYSZ + HEADERSZ > infilesize) + place = 0; + + offset = place ? HEADERSZ + (place - 1) * ENTRYSZ : infilesize; +*/ + if (place == 0 || place * ENTRYSZ + HEADERSZ > infilesize) + offset = infilesize; + else + offset = HEADERSZ + (place - 1) * ENTRYSZ; + + ereadinfile(outbuf, offset, infile); + + *(uint32_t *)(outbuf + HEADERSZSZ) = setgamecount( + (infilesize - HEADERSZ) / ENTRYSZ + 1); + + addrom(outbuf + offset, &rom); + + ereadinfile(outbuf + offset + ENTRYSZ, infilesize - offset, infile); + + if (!(outfile = fopen(out, "w"))) + die("Can't open output file %s\n", out); + + if (fwrite(outbuf, 1, outbufsize, outfile) != + outbufsize) + die("Couldn't write all data to output file %s\n", out); + + free(outbuf); + + if (fclose(infile) == EOF) + die("There was an error while closing input file %s\n", in); + + /* already closed by fclose() + if (close(infd) == -1) + die("There was an error while closing input file %s\n", in); + */ + + if (fclose(outfile) == EOF) + die("There was an error while closing output file %s\n", out); + + return(0); +} diff --git a/arg.h b/arg.h @@ -0,0 +1,63 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][1]\ + && argv[0][0] == '-';\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +/* Handles obsolete -NUM syntax */ +#define ARGNUM case '0':\ + case '1':\ + case '2':\ + case '3':\ + case '4':\ + case '5':\ + case '6':\ + case '7':\ + case '8':\ + case '9' + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define ARGNUMF(base) (brk_ = 1, strtol(argv[0], NULL, (base))) + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/config.mk b/config.mk @@ -0,0 +1,14 @@ +# paths +PREFIX = /usr/local + +# includes and libs +INCS = -I. -I/usr/include +LIBS = -L/usr/lib + +# flags +CPPFLAGS += -D_POSIX_SOURCE +CFLAGS += -std=c99 -pedantic -Wall -Os -s ${INCS} ${CPPFLAGS} +LDFLAGS += -s ${LIBS} + +# compiler and linker +# CC = cc