taddrom.c - addrom - Simple tool for adding a rom entry to a Pandora's Box 3 list.dat
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
taddrom.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 }