X-Git-Url: https://git.draconx.ca/gitweb/liblbx.git/blobdiff_plain/00f5f0706e7552e86a28d9fd66df962e095e8576..00d3a7a19623637e8010ad5afc6975cd33ea28f6:/src/lbx.c
diff --git a/src/lbx.c b/src/lbx.c
index 20c32e7..d3fc011 100644
--- a/src/lbx.c
+++ b/src/lbx.c
@@ -1,3 +1,25 @@
+/*
+ * 2ooM: The Master of Orion II Reverse Engineering Project
+ * Library for working with LBX archive files.
+ * Copyright (C) 2006-2008 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 .
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include
#include
#include
@@ -5,11 +27,14 @@
#include
#include
+#include
+#include
+
#include "byteorder.h"
+#include "misc.h"
#include "lbx.h"
#define LBX_MAGIC 0x0000fead
-#define MIN(a,b) (((a)<(b))?(a):(b))
int lbx_errno = 0;
@@ -156,49 +181,12 @@ int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
return -1;
}
- snprintf(str, sizeof str, "%s.%03d", lbx->name, index);
+ snprintf(str, sizeof str, "%s.%03zu", lbx->name, index);
buf->name = str;
buf->size = lbx->offsets[index+1] - lbx->offsets[index];
return 0;
}
-/* Advance to the beginning of the index'th file by either fseek or reading. */
-static int _lbx_fseek(struct lbx_state *lbx, size_t base)
-{
- static unsigned char oblivion[1024];
- long dist;
-
- if (lbx->foff < base) {
- dist = base - lbx->foff;
- } else if (lbx->foff > base) {
- dist = -(long)(lbx->foff - base);
- } else {
- return 0;
- }
-
- if (fseek(lbx->f, dist, SEEK_CUR) == 0) {
- lbx->foff += dist;
- } else if (lbx->foff < base) {
- while (dist) {
- size_t rc, amt = MIN(sizeof oblivion, dist);
- rc = fread(oblivion, 1, amt, lbx->f);
- lbx->foff += rc;
- dist -= rc;
- if (rc < amt) {
- if (feof(lbx->f))
- lbx_errno = LBX_EEOF;
- else
- lbx_errno = -errno;
- return -1;
- }
- }
- } else {
- lbx_errno = -errno;
- return -1;
- }
- return 0;
-}
-
static size_t
_lbx_mextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
{
@@ -222,7 +210,7 @@ _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
assert(lbx->f);
- if (_lbx_fseek(lbx, base) == -1)
+ if (_lbx_fseek(lbx->f, &lbx->foff, base) == -1)
return 0;
while (len) {
@@ -265,12 +253,50 @@ size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
return _lbx_fextract(lbx, base, len, of);
}
+void *lbx_mmap(struct lbx_state *lbx, size_t index, size_t *len)
+{
+ unsigned char *mapping;
+ struct stat statbuf;
+ size_t base;
+
+ if (index >= lbx->nfiles) {
+ lbx_errno = LBX_ERANGE;
+ return NULL;
+ }
+
+ base = lbx->offsets[index];
+ *len = lbx->offsets[index+1] - lbx->offsets[index];
+
+ if (lbx->mem)
+ return lbx->mem + base;
+
+ if (fstat(fileno(lbx->f), &statbuf) == -1) {
+ lbx_errno = -errno;
+ return NULL;
+ }
+
+ mapping = mmap(NULL, statbuf.st_size, PROT_READ, 0, fileno(lbx->f), 0);
+ if (mapping == MAP_FAILED) {
+ lbx_errno = -errno;
+ return NULL;
+ }
+
+ lbx->mem = mapping;
+ lbx->memsize = statbuf.st_size;
+ return mapping + base;
+}
+
void lbx_close(struct lbx_state *lbx)
{
if (!lbx) return;
- if (lbx->f)
+ if (lbx->f) {
fclose(lbx->f);
+ if (lbx->mem) {
+ munmap(lbx->mem, lbx->memsize);
+ }
+ }
+
free(lbx);
}
@@ -284,6 +310,7 @@ const char *lbx_strerror(void)
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";