]> git.draconx.ca Git - liblbx.git/blobdiff - src/lbx.c
Initial implementation of list and extract operations.
[liblbx.git] / src / lbx.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";