]> git.draconx.ca Git - liblbx.git/blobdiff - src/lbx.c
liblbx: Improve error handling in lbx_file_seek.
[liblbx.git] / src / lbx.c
index 17bf9769f0a670d938b67ed516e0043574543a25..1198ebbc2c0b13e08aa4cbb7c914ae431d4eb48c 100644 (file)
--- a/src/lbx.c
+++ b/src/lbx.c
@@ -1,7 +1,7 @@
 /*
  *  2ooM: The Master of Orion II Reverse Engineering Project
  *  Library for working with LBX archive files.
- *  Copyright (C) 2006-2008 Nick Bowler
+ *  Copyright © 2006-2010, 2013-2014 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
  *  You should have received a copy of the GNU General Public License
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-#ifdef HAVE_CONFIG_H
-#      include "config.h"
-#endif
-
+#include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "pack.h"
 #include "misc.h"
+#include "error.h"
 #include "lbx.h"
 
 #define LBX_MAGIC    0x0000fead
 #define LBX_HDR_SIZE 8
 
-int lbx_errno = 0;
+struct lbx_priv {
+       struct lbx pub;
 
-struct lbx_state {
        char *name;
 
        const struct lbx_file_ops *fops;
@@ -44,36 +42,35 @@ struct lbx_state {
 
        struct lbx_file_state *last_file;
 
-       unsigned short nfiles;
        unsigned long offsets[];
 };
 
 struct lbx_file_state {
        unsigned long base, limit, offset;
-       struct lbx_state *lbx;
+       struct lbx_priv *lbx;
        int eof;
 };
 
-static struct lbx_state *lbx_init(unsigned char hdr[static LBX_HDR_SIZE])
+static struct lbx_priv *lbx_init(unsigned char hdr[static LBX_HDR_SIZE])
 {
        unsigned short nfiles  = unpack_16_le(hdr+0);
        unsigned long  magic   = unpack_32_le(hdr+2);
        unsigned short version = unpack_16_le(hdr+6);
-       struct lbx_state *lbx;
+       struct lbx_priv *lbx;
 
        if (magic != LBX_MAGIC) {
-               lbx_errno = -LBX_EMAGIC;
+               lbx_error_raise(LBX_EMAGIC);
                return NULL;
        }
 
        lbx = malloc(sizeof *lbx + sizeof lbx->offsets[0] * (nfiles+1));
        if (!lbx) {
-               lbx_errno = -errno;
+               lbx_error_raise(LBX_ENOMEM);
                return NULL;
        }
 
-       *lbx = (struct lbx_state) {
-               .nfiles = nfiles,
+       *lbx = (struct lbx_priv) {
+               .pub = { .nfiles = nfiles, },
        };
 
        return lbx;
@@ -89,21 +86,22 @@ static char *str_dup(const char *s)
        return buf;
 }
 
-struct lbx_state *lbx_open(void *f, const struct lbx_file_ops *fops,
-                           int (*destructor)(void *), const char *name)
+struct lbx *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 = NULL;
+       struct lbx_priv *lbx = NULL;
        char *dupname = NULL;
 
        dupname = str_dup(name);
        if (!dupname) {
-               lbx_errno = -errno;
+               lbx_error_raise(LBX_ENOMEM);
                goto err;
        }
 
        if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) {
-               lbx_errno = -errno;
+               if (fops->eof(f))
+                       lbx_error_raise(LBX_EEOF);
                goto err;
        }
 
@@ -116,20 +114,19 @@ struct lbx_state *lbx_open(void *f, const struct lbx_file_ops *fops,
        lbx->fops = fops;
        lbx->f    = f;
 
-       for (unsigned i = 0; i <= lbx->nfiles; i++) {
+       for (unsigned i = 0; i <= lbx->pub.nfiles; i++) {
                unsigned char buf[4];
 
                if (fops->read(buf, sizeof buf, f) != sizeof buf) {
-                       lbx_errno = -errno;
                        if (fops->eof(f))
-                               lbx_errno = LBX_EEOF;
+                               lbx_error_raise(LBX_EEOF);
                        goto err;
                }
 
                lbx->offsets[i] = unpack_32_le(buf);
        }
 
-       return lbx;
+       return &lbx->pub;
 err:
        free(dupname);
        free(lbx);
@@ -162,21 +159,24 @@ static char *last_component(const char *name)
        return c+1;
 }
 
-struct lbx_state *lbx_fopen(const char *file)
+struct lbx *lbx_fopen(const char *file)
 {
        const char *name = last_component(file);
        struct lbx_pipe_state *p;
        FILE *f;
 
        f = fopen(file, "rb");
-       if (!f)
+       if (!f) {
+               lbx_error_raise(-errno);
                return NULL;
+       }
 
        if (fseek(f, 0, SEEK_CUR) == 0)
                return lbx_open(f, &lbx_default_fops, file_close, name);
 
        p = malloc(sizeof *p);
        if (!p) {
+               lbx_error_raise(LBX_ENOMEM);
                fclose(f);
                return NULL;
        }
@@ -185,29 +185,26 @@ struct lbx_state *lbx_fopen(const char *file)
        return lbx_open(p, &lbx_pipe_fops, pipe_close, name);
 }
 
-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)
+int lbx_file_stat(struct lbx *pub, unsigned fileno, struct lbx_statbuf *buf)
 {
+       struct lbx_priv *lbx = (struct lbx_priv *)pub;
        static char str[256]; /* FIXME */
 
-       if (index >= lbx->nfiles) {
+       if (fileno >= lbx->pub.nfiles) {
+               lbx_error_raise(LBX_EINVAL);
                buf->name = NULL;
-               lbx_errno = LBX_ERANGE;
                return -1;
        }
 
-       snprintf(str, sizeof str, "%s.%03zu", lbx->name, index);
+       snprintf(str, sizeof str, "%s.%03u", lbx->name, fileno);
        buf->name = str;
-       buf->size = lbx->offsets[index+1] - lbx->offsets[index];
+       buf->size = lbx->offsets[fileno+1] - lbx->offsets[fileno];
        return 0;
 }
 
-int lbx_close(struct lbx_state *lbx)
+int lbx_close(struct lbx *pub)
 {
+       struct lbx_priv *lbx = (struct lbx_priv *)pub;
        int rc = 0;
 
        if (lbx && lbx->dtor)
@@ -218,24 +215,24 @@ int lbx_close(struct lbx_state *lbx)
        return rc;
 }
 
-struct lbx_file_state *lbx_file_open(struct lbx_state *lbx, unsigned fileno)
+struct lbx_file_state *lbx_file_open(struct lbx *pub, unsigned fileno)
 {
+       struct lbx_priv *lbx = (struct lbx_priv *)pub;
        struct lbx_file_state *state;
 
-       if (fileno >= lbx->nfiles) {
-               lbx_errno = LBX_ERANGE;
+       if (fileno >= lbx->pub.nfiles) {
+               lbx_error_raise(LBX_EINVAL);
                return NULL;
        }
 
        lbx->last_file = NULL;
        if (lbx->fops->seek(lbx->f, lbx->offsets[fileno], SEEK_SET) != 0) {
-               lbx_errno = -errno;
                return NULL;
        }
 
        state = malloc(sizeof *state);
        if (!state) {
-               lbx_errno = -errno;
+               lbx_error_raise(LBX_ENOMEM);
                return NULL;
        }
 
@@ -285,14 +282,21 @@ int lbx_file_seek(struct lbx_file_state *f, long offset, int whence)
        case SEEK_END:
                pos = f->limit + offset;
                break;
+       default:
+               lbx_error_raise(LBX_EINVAL);
+               return -1;
        }
 
-       if (pos > f->limit)
+       if (pos > f->limit) {
+               lbx_error_raise(LBX_EINVAL);
                return -1;
+       }
 
        f->lbx->last_file = NULL;
        if (fops->seek(f->lbx->f, f->base + pos, SEEK_SET) != 0)
                return -1;
+
+       f->offset = pos;
        f->lbx->last_file = f;
        f->eof = 0;
 
@@ -315,19 +319,3 @@ void lbx_file_close(struct lbx_file_state *f)
                f->lbx->last_file = NULL;
        free(f);
 }
-
-const char *lbx_strerror(void)
-{
-       if (lbx_errno < 0)
-               return strerror(-lbx_errno);
-
-       switch (lbx_errno) {
-       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";
-       case LBX_EFORMAT:  return "Invalid file format";
-       }
-
-       return "Unknown error";
-}