]> git.draconx.ca Git - liblbx.git/commitdiff
Initial implementation of list and extract operations.
authorNick Bowler <draconx@gmail.com>
Sat, 22 Dec 2007 23:40:41 +0000 (18:40 -0500)
committerNick Bowler <draconx@gmail.com>
Sat, 22 Dec 2007 23:40:41 +0000 (18:40 -0500)
src/lbx.c
src/lbx.h
src/lbxtool.c

index 6e7b9eef790af843107e4a316163895d404e9df9..3eac7080faadf6a13093754515160165e51ecbd8 100644 (file)
--- a/src/lbx.c
+++ b/src/lbx.c
@@ -8,6 +8,7 @@
 #include "lbx.h"
 
 #define LBX_MAGIC 0x0000fead
+#define MIN(a,b) (((a)<(b))?(a):(b))
 
 int lbx_errno = 0;
 
@@ -89,6 +90,104 @@ size_t lbx_numfiles(struct lbx_state *lbx)
        return lbx->nfiles;
 }
 
+int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
+{
+       static char str[256]; /* FIXME */
+
+       if (index >= lbx->nfiles) {
+               buf->name = NULL;
+               lbx_errno = LBX_ERANGE;
+               return -1;
+       }
+
+       snprintf(str, sizeof str, "%s.%03d", lbx->name, index);
+       buf->name = str;
+       buf->size = lbx->offsets[index+1] - lbx->offsets[index];
+       return 0;
+}
+
+/*
+ * Read and discard len bytes from the file.  On success, returns 0.  On
+ * failure, returns -1 and sets lbx_errno.
+ */
+static int skipdata(FILE *f, size_t len)
+{
+       unsigned char buf[1024];
+       
+       while (len) {
+               if (fread(buf, MIN(sizeof buf, len), 1, f) != 1) {
+                       if (feof(f)) {
+                               lbx_errno = LBX_EEOF;
+                       } else {
+                               lbx_errno = -errno;
+                       }
+                       return -1;
+               }
+               len -= MIN(sizeof buf, len);
+       }
+
+       return 0;
+}
+
+size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
+{
+       unsigned char buf[1024];
+       size_t rc, written = 0, base, len;
+
+       if (index >= lbx->nfiles) {
+               lbx_errno = LBX_ERANGE;
+               return 0;
+       }
+       
+       base = lbx->offsets[index];
+       len  = lbx->offsets[index+1] - lbx->offsets[index];
+
+       /* Seek to the beginning of the file. */
+       if (lbx->foff != base) {
+               int seekrc;
+               long dist = (lbx->foff < base) ?  (base - lbx->foff)
+                                              : -(lbx->foff - base);
+
+               seekrc = fseek(lbx->f, dist, SEEK_CUR);
+               if (seekrc == -1 && lbx->foff < base) {
+                       if (skipdata(lbx->f, dist) == -1) {
+                               /* lbx_errno set by skipdata */
+                               return 0;
+                       }
+               } else if (seekrc == -1) {
+                       lbx_errno = -errno;
+                       return 0;
+               }
+               lbx->foff += dist; /* FIXME: failed skipdata breaks this. */
+       }
+
+       /* Copy file data */
+       while (len) {
+               size_t amt = MIN(sizeof buf, len);
+
+               rc = fread(buf, 1, amt, lbx->f);
+               lbx->foff += rc;
+               len -= rc;
+               if (rc < amt) {
+                       if (feof(lbx->f)) {
+                               lbx_errno = LBX_EEOF;
+                       } else {
+                               lbx_errno = -errno;
+                       }
+                       break;
+               }
+
+               rc = fwrite(buf, 1, amt, of);
+               written += rc;
+               if (rc < amt) {
+                       lbx_errno = -errno;
+                       break;
+               }
+       }
+
+       return written;
+}
+
 void lbx_close(struct lbx_state *lbx)
 {
        if (!lbx) return;
@@ -106,6 +205,7 @@ const char *lbx_strerror(void)
        case LBX_ESUCCESS: return "Success";
        case LBX_EMAGIC:   return "Bad magic number";
        case LBX_EEOF:     return "Unexpected end-of-file";
+       case LBX_ERANGE:   return "Index out of range";
        }
 
        return "Unknown error";
index 1911cd759012f3ebeb835510a597d75fd16a2051..19848d25ab93e2481509bab5bd5711fc6b48cdaa 100644 (file)
--- a/src/lbx.h
+++ b/src/lbx.h
@@ -8,18 +8,28 @@ enum {
        LBX_ESUCCESS,
        LBX_EMAGIC,
        LBX_EEOF,
+       LBX_ERANGE,
 };
 extern int lbx_errno;
 
 /* Opaque */
 typedef struct lbx_state LBX;
 
-/* File operations */
+struct lbx_statbuf {
+       const char *name;
+       size_t size;
+};
+
+/* Archive operations */
 LBX   *lbx_fopen(FILE *, const char *);
 LBX   *lbx_open(const char *);
 void   lbx_close(LBX *);
 size_t lbx_numfiles(LBX *);
 
+/* File operations */
+int    lbx_stat(LBX *, size_t, struct lbx_statbuf *);
+size_t lbx_extract(LBX *, size_t, FILE *);
+
 /* Misc operations */
 const char *lbx_strerror(void);
 
index 96c8ddd06e8ef87c7a016f2923e4cfac9967fa98..a220cea67d858fd881939a3396f9ad0683cacd37 100644 (file)
@@ -18,17 +18,78 @@ enum {
 };
 
 int list(FILE *f, const char *name, int verbose) {
-       LBX *lbx = lbx_fopen(f, name);
+       LBX *lbx;
+       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);
+       }
+
+       for (i = 0; i < nfiles; i++) {
+               struct lbx_statbuf stat;
+
+               lbx_stat(lbx, i, &stat);
+               printf("%s", stat.name);
+               if (verbose) {
+                       printf(" size=%zu bytes", stat.size);
+               }
+
+               putchar('\n');
+       }
+
+       lbx_close(lbx);
+       return EXIT_SUCCESS;
+}
+
+int extract(FILE *f, const char *name, int verbose) {
+       LBX *lbx;
+       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: %zd\n", lbx_numfiles(lbx));
+               printf("Files in archive: %zu\n", nfiles);
+       }
+
+       for (i = 0; i < nfiles; i++) {
+               struct lbx_statbuf stat;
+               size_t rc;
+               FILE *of;
+
+               lbx_stat(lbx, i, &stat);
+               of = fopen(stat.name, "wbx");
+               if (!of) {
+                       errmsg("failed to create output file %s: %m.\n",
+                                                            stat.name);
+                       break;
+               }
+
+               if (verbose) printf("extracting %s...\n", stat.name);
+               rc = lbx_extract(lbx, i, of);
+               if (rc < stat.size) {
+                       errmsg("error extracting %s: %s.\n",
+                              stat.name, lbx_strerror());
+                       break;
+               }
+               if (verbose) printf("wrote %zu bytes.\n", rc);
        }
 
        lbx_close(lbx);
+       return EXIT_SUCCESS;
 }
 
 int main(int argc, char **argv)
@@ -88,7 +149,7 @@ int main(int argc, char **argv)
        case MODE_LIST:
                return list(f, name, verbose);
        case MODE_EXTRACT:
-               return EXIT_SUCCESS;
+               return extract(f, name, verbose);
        }
 
        fprintf(stderr, "%s: you must specify a mode.\n", progname);