URI: 
       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 }