]> git.draconx.ca Git - liblbx.git/commitdiff
liblbx: Parameterise I/O functions to allow custom streams.
authorNick Bowler <nbowler@draconx.ca>
Thu, 4 Feb 2010 01:47:40 +0000 (20:47 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 4 Feb 2010 05:11:44 +0000 (00:11 -0500)
This eliminates the need for lbx_mopen and friends, so remove them.  We
also now leave it to the caller to handle "seeking" on pipes, to
eliminate yet another hack.  Only the core LBX handling code is updated
for now.

src/Makefile.inc
src/fops.c [new file with mode: 0644]
src/lbx.c
src/lbx.h
src/lbxtool.c

index fd3d0a88eeda1019b53170f76b5c3ec0ecd51736..dee29587b63e97238ff2a171eeb6e22c329d7580 100644 (file)
@@ -10,7 +10,7 @@ lbx_HEADERS = src/lbx.h src/image.h
 noinst_HEADERS += src/byteorder.h src/misc.h src/tools.h src/pack.h
 
 lib_LTLIBRARIES  += liblbx.la
-liblbx_la_SOURCES = src/misc.c src/lbx.c src/image.c src/pack.c
+liblbx_la_SOURCES = src/misc.c src/lbx.c src/fops.c src/image.c src/pack.c
 
 bin_PROGRAMS    += lbxtool
 lbxtool_SOURCES  = src/lbxtool.c
diff --git a/src/fops.c b/src/fops.c
new file mode 100644 (file)
index 0000000..2ae6c61
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  2ooM: The Master of Orion II Reverse Engineering Project
+ *  Default file operations structures for liblbx.
+ *  Copyright (C) 2010 Nick Bowler
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdio.h>
+
+#include "misc.h"
+#include "lbx.h"
+
+/* Default I/O operations for ordinary files. */
+static size_t file_read(void *buf, size_t size, void *handle)
+{
+       return fread(buf, 1, size, (FILE *)handle);
+}
+
+static int file_seek(void *handle, long offset, int whence)
+{
+       return fseek((FILE *)handle, offset, whence);
+}
+
+static long file_tell(void *handle)
+{
+       return ftell((FILE *)handle);
+}
+
+static int file_eof(void *handle)
+{
+       return feof((FILE *)handle);
+}
+
+const struct lbx_file_ops lbx_default_fops = {
+       .read = file_read,
+       .seek = file_seek,
+       .tell = file_tell,
+       .eof  = file_eof,
+};
+
+/* Read function for pipes that tracks the number of bytes read. */
+static size_t pipe_read(void *buf, size_t size, void *handle)
+{
+       struct lbx_pipe_state *state = handle;
+       size_t rc;
+
+       rc = fread(buf, 1, size, state->f);
+       state->offset += rc;
+       return rc;
+}
+
+/* Seek function for pipes that reads data into the void. */
+static int pipe_seek(void *handle, long offset, int whence)
+{
+       struct lbx_pipe_state *state = handle;
+       long distance;
+
+       distance = offset - state->offset;
+       if (distance < 0)
+               return -1;
+
+       while (distance > 0) {
+               static unsigned char oblivion[1024];
+               size_t rc, amount = MIN(sizeof oblivion, distance);
+
+               rc = pipe_read(oblivion, amount, handle);
+               distance -= rc;
+
+               if (rc < amount)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static long pipe_tell(void *handle)
+{
+       struct lbx_pipe_state *state = handle;
+
+       return state->offset;
+}
+
+static int pipe_eof(void *handle)
+{
+       struct lbx_pipe_state *state = handle;
+
+       return feof(state->f);
+}
+
+const struct lbx_file_ops lbx_pipe_fops = {
+       .read = pipe_read,
+       .seek = pipe_seek,
+       .tell = pipe_tell,
+       .eof  = pipe_eof,
+};
index fc52680c47c0a57c19fec6a074de4ff0af5f884c..4b5d7f3fe8f483c9003df780b6fa6f44fd6ba6c6 100644 (file)
--- a/src/lbx.c
+++ b/src/lbx.c
@@ -42,10 +42,9 @@ int lbx_errno = 0;
 struct lbx_state {
        const char *name;
 
-       unsigned char *mem;
-       size_t memsize;
-       FILE *f;
-       long foff;
+       const struct lbx_file_ops *fops;
+       int (*dtor)(void *handle);
+       void *f;
 
        uint16_t nfiles;
        uint32_t offsets[];
@@ -76,12 +75,13 @@ static struct lbx_state *lbx_init(unsigned char hdr[static LBX_HDR_SIZE])
        return lbx;
 }
 
-struct lbx_state *lbx_fopen(FILE *f, const char *name)
+struct lbx_state *lbx_open(void *f, const struct lbx_file_ops *fops,
+                           int (*destructor)(void *), const char *name)
 {
        unsigned char hdr_buf[LBX_HDR_SIZE];
        struct lbx_state *lbx;
 
-       if (fread(hdr_buf, 1, sizeof hdr_buf, f) != sizeof hdr_buf) {
+       if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) {
                lbx_errno = -errno;
                return NULL;
        }
@@ -90,79 +90,31 @@ struct lbx_state *lbx_fopen(FILE *f, const char *name)
        if (!lbx)
                return NULL;
 
+       lbx->dtor = destructor;
        lbx->name = name;
+       lbx->fops = fops;
        lbx->f    = f;
-       lbx->foff = sizeof hdr_buf;
 
        for (unsigned i = 0; i <= lbx->nfiles; i++) {
                unsigned char buf[4];
 
-               if (fread(buf, 1, sizeof buf, f) != sizeof buf) {
+               if (fops->read(buf, sizeof buf, f) != sizeof buf) {
                        lbx_errno = -errno;
-                       if (feof(f))
+                       if (fops->eof(f))
                                lbx_errno = LBX_EEOF;
                        free(lbx);
                        return NULL;
                }
 
                lbx->offsets[i] = unpack_32_le(buf);
-               lbx->foff += sizeof buf;
        }
 
        return lbx;
 }
 
-static int _lbx_memcpy(void *dest, struct lbx_state *src, size_t size)
+struct lbx_state *lbx_fopen(FILE *f, const char *name)
 {
-       if (src->foff + size > src->memsize)
-               return -1;
-       memcpy(dest, src->mem + src->foff, size);
-       src->foff += size;
-       return 0;
-}
-
-struct lbx_state *lbx_mopen(void *_mem, size_t size, const char *name)
-{
-       struct lbx_state *new = NULL;
-       struct lbx_state tmp = { .mem = _mem, .memsize = size };
-       uint16_t nfiles, version;
-       uint32_t magic;
-
-       if (_lbx_memcpy(&nfiles,  &tmp, sizeof nfiles)  == -1) goto eof;
-       if (_lbx_memcpy(&magic,   &tmp, sizeof magic)   == -1) goto eof;
-       if (_lbx_memcpy(&version, &tmp, sizeof version) == -1) goto eof;
-
-       nfiles  = letohs(nfiles);
-       magic   = letohl(magic);
-       version = letohs(version);
-
-       if (magic != LBX_MAGIC) {
-               lbx_errno = LBX_EMAGIC;
-               return NULL;
-       }
-       
-       new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
-       if (!new) {
-               lbx_errno = -errno;
-               return NULL;
-       }
-       
-       *new = (struct lbx_state){
-               .name    = name,
-               .nfiles  = nfiles,
-               .mem     = _mem,
-               .memsize = size,
-               .foff    = tmp.foff,
-       };
-       
-       if (_lbx_memcpy(new->offsets, new, (nfiles+1)*(sizeof *new->offsets)))
-               goto eof;
-
-       return new;
-eof:
-       free(new);
-       lbx_errno = LBX_EEOF;
-       return NULL;
+       return lbx_open(f, &lbx_default_fops, NULL, name);
 }
 
 size_t lbx_numfiles(struct lbx_state *lbx)
@@ -186,21 +138,6 @@ int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
        return 0;
 }
 
-static size_t
-_lbx_mextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
-{
-       size_t rc;
-
-       assert(lbx->mem);
-       assert(base + len <= lbx->memsize);
-
-       rc = fwrite(lbx->mem + base, 1, len, of);
-       if (rc < len)
-               lbx_errno = -errno;
-
-       return rc;
-}
-
 static size_t
 _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
 {
@@ -209,17 +146,18 @@ _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
 
        assert(lbx->f);
 
-       if (_lbx_fseek(lbx->f, &lbx->foff, base) == -1)
+       if (lbx->fops->seek(lbx->f, base, SEEK_SET) != 0) {
+               lbx_errno = -errno;
                return 0;
+       }
        
        while (len) {
                size_t amt = MIN(len, sizeof buf);
 
-               rc = fread(buf, 1, amt, lbx->f);
-               lbx->foff += rc;
+               rc = lbx->fops->read(buf, amt, lbx->f);
                len -= rc;
                if (rc < amt) {
-                       if (feof(lbx->f)) lbx_errno = LBX_EEOF;
+                       if (lbx->fops->eof(lbx->f)) lbx_errno = LBX_EEOF;
                        else lbx_errno = -errno;
                        break;
                }
@@ -246,9 +184,6 @@ size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
        
        base = lbx->offsets[index];
        len  = lbx->offsets[index+1] - lbx->offsets[index];
-
-       if (lbx->mem)
-               return _lbx_mextract(lbx, base, len, of);
        return _lbx_fextract(lbx, base, len, of);
 }
 
@@ -256,13 +191,10 @@ int lbx_close(struct lbx_state *lbx)
 {
        int rc = 0;
 
-       if (!lbx)
-               return 0;
-
-       if (lbx->f)
-               rc = fclose(lbx->f);
-
+       if (lbx && lbx->dtor)
+               rc = lbx->dtor(lbx->f);
        free(lbx);
+
        return rc;
 }
 
index 89d4bb4201bd31e471374c964524e520be1b4512..a788318bda0381840f958b83ca3d8e3de747f6b0 100644 (file)
--- a/src/lbx.h
+++ b/src/lbx.h
@@ -13,6 +13,24 @@ enum {
 };
 extern int lbx_errno;
 
+struct lbx_file_ops {
+       size_t (*read)(void *buf, size_t size, void *handle);
+       int    (*seek)(void *handle, long offset, int whence);
+       long   (*tell)(void *handle);
+       int    (*eof) (void *handle);
+};
+
+struct lbx_pipe_state {
+       FILE *f;
+       long offset;
+};
+
+/* Default I/O operations for ordinary files. */
+extern const struct lbx_file_ops lbx_default_fops;
+
+/* I/O operations for un-seekable files (e.g. pipes). */
+extern const struct lbx_file_ops lbx_pipe_fops;
+
 /* Opaque */
 typedef struct lbx_state LBX;
 
@@ -22,6 +40,8 @@ struct lbx_statbuf {
 };
 
 /* Archive operations */
+LBX   *lbx_open(void *handle, const struct lbx_file_ops *fops,
+                int (*destructor)(void *handle), const char *name);
 LBX   *lbx_fopen(FILE *, const char *);
 LBX   *lbx_mopen(void *, size_t, const char *);
 int    lbx_close(LBX *);
index 47ee37b47a44cddcf265597313ec651a34c07217..d070e8f188feb04e0fd26b9bdc9a32c268aef569 100644 (file)
@@ -26,6 +26,7 @@
 #include "tools.h"
 #include "lbx.h"
 
+
 static void printusage(void)
 {
        puts("usage: lbxtool [-l|-x] [-v] [-f path] [file ...]");
@@ -67,17 +68,10 @@ int filematch(char **argv, const char *name)
        return i ? -1: 0;
 }
 
-int list(FILE *f, const char *name, int verbose, char **argv) {
-       LBX *lbx;
+int list(LBX *lbx, const char *name, int verbose, char **argv) {
        size_t nfiles;
        unsigned int i;
 
-       lbx = lbx_fopen(f, name);
-       if (!lbx) {
-               errmsg("failed to open archive: %s.\n", lbx_strerror());
-               return EXIT_FAILURE;
-       }
-
        nfiles = lbx_numfiles(lbx);
        if (verbose) {
                printf("Files in archive: %zu\n", nfiles);
@@ -91,7 +85,7 @@ int list(FILE *f, const char *name, int verbose, char **argv) {
                switch (filematch(argv, stat.name)) {
                case -1: continue;
                case  0: break;
-               default: goto err;
+               default: return EXIT_FAILURE;
                }
 
                printf("%s", stat.name);
@@ -102,24 +96,13 @@ int list(FILE *f, const char *name, int verbose, char **argv) {
                putchar('\n');
        }
 
-       lbx_close(lbx);
        return EXIT_SUCCESS;
-err:
-       lbx_close(lbx);
-       return EXIT_FAILURE;
 }
 
-int extract(FILE *f, const char *name, int verbose, char **argv) {
-       LBX *lbx;
+int extract(LBX *lbx, const char *name, int verbose, char **argv) {
        size_t nfiles;
        unsigned int i;
 
-       lbx = lbx_fopen(f, name);
-       if (!lbx) {
-               errmsg("failed to open archive: %s.\n", lbx_strerror());
-               return EXIT_FAILURE;
-       }
-
        nfiles = lbx_numfiles(lbx);
        if (verbose) {
                printf("Files in archive: %zu\n", nfiles);
@@ -136,14 +119,14 @@ int extract(FILE *f, const char *name, int verbose, char **argv) {
                switch (filematch(argv, stat.name)) {
                case -1: continue;
                case  0: break;
-               default: goto err;
+               default: return EXIT_FAILURE;
                }
 
                of = fopen(stat.name, "wbx");
                if (!of) {
                        errmsg("failed to create output file %s: %m.\n",
                                                             stat.name);
-                       goto err;
+                       return EXIT_FAILURE;
                }
 
                if (verbose) printf("extracting %s...\n", stat.name);
@@ -152,24 +135,20 @@ int extract(FILE *f, const char *name, int verbose, char **argv) {
                        if (rc == 0) remove(stat.name);
                        errmsg("error extracting %s: %s.\n",
                               stat.name, lbx_strerror());
-                       goto err;
+                       return EXIT_FAILURE;
                }
                if (verbose) printf("wrote %zu bytes.\n", rc);
        }
 
-       lbx_close(lbx);
        return EXIT_SUCCESS;
-err:
-       lbx_close(lbx);
-       return EXIT_FAILURE;
 }
 
 int main(int argc, char **argv)
 {
-       int mode = MODE_NONE, verbose = 0;
+       int mode = MODE_NONE, verbose = 0, opt, rc = EXIT_FAILURE;
+       struct lbx_pipe_state state = { .f = stdin };
        const char *name = "stdin";
-       FILE *f  = stdin;
-       int opt;
+       LBX *lbx;
 
        static const char         *sopts   = "lxf:i:vV";
        static const struct option lopts[] = {
@@ -204,8 +183,7 @@ int main(int argc, char **argv)
                        name = strrchr(optarg, '/');
                        name = name ? name+1 : optarg;
 
-                       f = fopen(optarg, "rb");
-                       if (!f) {
+                       if (!freopen(optarg, "rb", state.f)) {
                                errmsg("failed to open file %s: %m\n", optarg);
                                return EXIT_FAILURE;
                        }
@@ -230,13 +208,27 @@ int main(int argc, char **argv)
                }
        }
 
+       if (fseek(state.f, 0, SEEK_CUR) == 0)
+               lbx = lbx_open(state.f, &lbx_default_fops, NULL, name);
+       else
+               lbx = lbx_open(&state, &lbx_pipe_fops, NULL, name);
+
+       if (!lbx) {
+               errmsg("failed to open archive: %s.\n", lbx_strerror());
+               return EXIT_FAILURE;
+       }
+
        switch (mode) {
        case MODE_LIST:
-               return list(f, name, verbose, &argv[optind]);
+               rc = list(lbx, name, verbose, &argv[optind]);
+               break;
        case MODE_EXTRACT:
-               return extract(f, name, verbose, &argv[optind]);
+               rc = extract(lbx, name, verbose, &argv[optind]);
+               break;
+       default:
+               fprintf(stderr, "%s: you must specify a mode.\n", progname);
        }
 
-       fprintf(stderr, "%s: you must specify a mode.\n", progname);
-       return EXIT_FAILURE;
+       lbx_close(lbx);
+       return rc;
 }