addrom

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

addrom.c (4722B)


      1 #include <sys/types.h>
      2 #include <sys/stat.h>
      3 
      4 #include <fcntl.h>
      5 #include <inttypes.h>
      6 #include <libgen.h>
      7 #include <stdarg.h>
      8 #include <stdint.h>
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <unistd.h>
     13 
     14 #include "arg.h"
     15 
     16 #define HEADERSZSZ 4
     17 #define GAMECNTSZ  4
     18 #define HEADERSZ  16
     19 #define CHTITLESZ 64
     20 #define ENTITLESZ 32
     21 #define ROMNAMESZ 16
     22 #define MAGICSZ    8
     23 #define ENTRYSZ   (CHTITLESZ + ENTITLESZ + ROMNAMESZ + MAGICSZ)
     24 
     25 #define MAGIC     0x0000000000000000
     26 
     27 typedef struct {
     28 	char *chtitle;
     29 	char *entitle;
     30 	char *romname;
     31 } Rom;
     32 
     33 char *argv0;
     34 static char *in, *out;
     35 static intmax_t place;
     36 
     37 static void
     38 die(const char *errstr, ...)
     39 {
     40 	va_list ap;
     41 
     42 	va_start(ap, errstr);
     43 	vfprintf(stderr, errstr, ap);
     44 	va_end(ap);
     45 
     46 	exit(1);
     47 }
     48 
     49 static void
     50 addrom(char *datfile, const Rom *rom)
     51 {
     52 	ssize_t pos = 0;
     53 
     54 	if (rom->chtitle)
     55 		strncpy(datfile + pos, rom->chtitle, CHTITLESZ);
     56 	pos += CHTITLESZ;
     57 	if (rom->entitle)
     58 		strncpy(datfile + pos, rom->entitle, ENTITLESZ);
     59 	pos += ENTITLESZ;
     60 	if (rom->romname)
     61 		strncpy(datfile + pos, rom->romname, ROMNAMESZ);
     62 	pos += ROMNAMESZ;
     63 	*(uint64_t *)(datfile + pos) = MAGIC;
     64 }
     65 
     66 static uint32_t
     67 getbingamecount(uint64_t n)
     68 {
     69 	return (n << 32 << 6) / 0x88888888;
     70 }
     71 
     72 static void
     73 ereadinfile(char *datbuf, const ssize_t size, FILE *infile)
     74 {
     75 	if (fread(datbuf, 1, size, infile) != size)
     76 		die("Couldn't read %zu bytes of input file %s\n", size, in);
     77 }
     78 
     79 static void *
     80 ecalloc(const ssize_t size)
     81 {
     82 	char *buf;
     83 
     84 	if (!(buf = calloc(size, 1)))
     85 		die("Can't allocate enough memory for buffer\n");
     86 
     87 	return buf;
     88 }
     89 
     90 static void
     91 usage(void)
     92 {
     93 	die("usage: %s [-c title] [-e title] [-i file] [-n position] -o file -r name\n"
     94 	    "       %s [-c title] [-e title] -i file [-n position] [-o file] -r name\n",
     95 	    basename(argv0), basename(argv0));
     96 }
     97 
     98 int
     99 main(int argc, char *argv[])
    100 {
    101 	struct stat st;
    102 	Rom rom = { 0 };
    103 	off_t infilesize;
    104 	size_t outbufsize;
    105 	ssize_t offset;
    106 	FILE *infile, *outfile;
    107 	char *outbuf;
    108 	int infd;
    109 
    110 	ARGBEGIN {
    111 	case 'c':
    112 		rom.chtitle = EARGF(usage());
    113 		if (strlen(rom.chtitle) > CHTITLESZ)
    114 			die("Chinese title must be less then than %zu bytes: "
    115 			    "%s\n", CHTITLESZ, rom.chtitle);
    116 		break;
    117 	case 'e':
    118 		rom.entitle = EARGF(usage());
    119 		if (strlen(rom.entitle) > ENTITLESZ)
    120 			die("English title must be less then than %zu bytes: "
    121 			    "%s\n", ENTITLESZ, rom.entitle);
    122 		break;
    123 	case 'i':
    124 		in = EARGF(usage());
    125 		break;
    126 	case 'n':
    127 		place = strtoimax(EARGF(usage()), NULL, 10);
    128 		if (place < 1)
    129 			die("Place must be at least 1: %d\n", place);
    130 		break;
    131 	case 'o':
    132 		out = EARGF(usage());
    133 		break;
    134 	case 'r':
    135 		rom.romname = EARGF(usage());
    136 		if (strlen(rom.romname) > ROMNAMESZ)
    137 			die("Rom name must be less then than %zu bytes: %s\n",
    138 			    ROMNAMESZ, rom.romname);
    139 		break;
    140 	default:
    141 		usage();
    142 		break;
    143 	} ARGEND
    144 
    145 	if (!(in || out) || !rom.romname)
    146 		usage();
    147 
    148 	if (out && access(out, F_OK) != -1)
    149 		die("Output file %s exists and will not be overwritten\n",
    150 		    out);
    151 
    152 	/* create and populate buffer */
    153 	if (in) { /* from existing file */
    154 		if ((infd = open(in, out ? O_RDONLY : O_RDWR)) == -1)
    155 			die("Can't open input file %s\n", in);
    156 
    157 		if (fstat(infd, &st) == -1 || !S_ISREG(st.st_mode))
    158 			die("Input file %s is not a regular file\n", in);
    159 
    160 		if ((infilesize = st.st_size) < HEADERSZ)
    161 			die("Corrupted input file %s\n", in);
    162 
    163 		if (!(infile = fdopen(infd, out ? "r" : "r+")))
    164 			die("Can't open input file %s\n", in);
    165 
    166 		outbufsize = infilesize + ENTRYSZ;
    167 
    168 		outbuf = ecalloc(outbufsize);
    169 
    170 		if (place == 0 || place * ENTRYSZ + HEADERSZ > infilesize)
    171 			offset = infilesize;
    172 		else
    173 			offset = HEADERSZ + (place - 1) * ENTRYSZ;
    174 
    175 		ereadinfile(outbuf, offset, infile);
    176 
    177 		addrom(outbuf + offset, &rom);
    178 
    179 		ereadinfile(outbuf + offset + ENTRYSZ, infilesize - offset,
    180 		    infile);
    181 	} else { /* from scratch, position is ignored */
    182 		outbufsize = HEADERSZ + ENTRYSZ;
    183 
    184 		outbuf = ecalloc(outbufsize);
    185 
    186 		offset = HEADERSZ;
    187 
    188 		addrom(outbuf + offset, &rom);
    189 	}
    190 
    191 	*(uint32_t *)(outbuf) = HEADERSZ;
    192 	*(uint32_t *)(outbuf + HEADERSZSZ) =
    193 	    getbingamecount((outbufsize - HEADERSZ) / ENTRYSZ);
    194 
    195 	/* write out buffer */
    196 	if (out && !(outfile = fopen(out, "w")))
    197 		die("Can't open output file %s\n", out);
    198 	else if (!out && fseeko(infile, 0, SEEK_SET) == -1)
    199 		die("Couldn't seek input file %s\n", in);
    200 
    201 	if (fwrite(outbuf, 1, outbufsize, out ? outfile : infile) !=
    202 	    outbufsize)
    203 		die("Couldn't write all data to file %s\n", out ? out : in);
    204 
    205 	if (in && fclose(infile) == EOF)
    206 		fprintf(stderr, "There was an error while closing input file "
    207 		    "%s\n", in);
    208 
    209 	if (out && fclose(outfile) == EOF)
    210 		fprintf(stderr, "There was an error while closing output file "
    211 		    "%s\n", out);
    212 
    213 	free(outbuf);
    214 
    215 	return(0);
    216 }