unsigned short frames, leadin;
unsigned short palstart, palcount;
- FILE *f;
- long foff, paloff;
+ const struct lbx_file_ops *fops;
+ int (*dtor)(void *handle);
+ void *f;
+
+ long paloff;
int currentframe;
int currentx, currenty;
return img;
}
-struct lbx_image *lbximg_fopen(FILE *f)
+struct lbx_image *lbximg_open(void *f, const struct lbx_file_ops *fops,
+ int (*destructor)(void *))
{
unsigned char hdr_buf[HDR_LEN];
struct lbx_image *img;
- size_t rc;
- 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;
- if (feof(f))
+ if (fops->eof(f))
lbx_errno = LBX_EEOF;
return NULL;
}
return NULL;
img->f = f;
- img->foff = sizeof hdr_buf;
+ img->fops = fops;
+ img->dtor = destructor;
/*
* DEBUG ONLY. These assertions exist to catch otherwise valid image
for (unsigned i = 0; i <= img->frames; 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(img);
return NULL;
}
img->offsets[i] = unpack_32_le(buf);
- img->foff += 4;
}
if (img->flags & FLAG_PALETTE) {
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(img);
return NULL;
img->palstart = unpack_16_le(buf+0);
img->palcount = unpack_16_le(buf+2);
- img->foff += sizeof buf;
- img->paloff = img->foff;
+ img->paloff = fops->tell(f);
if (img->palstart + img->palcount > 256) {
lbx_errno = LBX_EFORMAT;
return img;
}
+struct lbx_image *lbximg_fopen(FILE *f)
+{
+ return lbximg_open(f, &lbx_default_fops, NULL);
+}
+
static int _lbx_drawrow(int first, struct lbx_image *img)
{
unsigned short type, count, yval, xval;
assert(img->framedata);
assert(img->mask);
- if (fread(buf, 1, sizeof buf, img->f) != sizeof buf)
+ if (img->fops->read(buf, sizeof buf, img->f) != sizeof buf)
goto readerr;
- img->foff += 4;
type = unpack_16_le(buf+0);
if (first) {
if (yval == 1000)
return 1;
- if (fread(buf, 1, sizeof buf, img->f) != sizeof buf)
+ if (img->fops->read(buf, sizeof buf, img->f) != sizeof buf)
goto readerr;
- img->foff += 4;
count = unpack_16_le(buf+0);
xval = unpack_16_le(buf+2);
memset(&img->mask[img->currenty][img->currentx], 1, count);
pos = &img->framedata[img->currenty][img->currentx];
- rc = fread(pos, 1, count, img->f);
+ rc = img->fops->read(pos, count, img->f);
img->currentx += rc;
- img->foff += rc;
if (rc < count)
goto readerr;
if (count % 2) {
- if (fread(buf, 1, 1, img->f) != 1)
+ if (img->fops->read(buf, 1, img->f) != 1)
goto readerr;
- img->foff += 1;
}
return 0;
readerr:
- if (feof(img->f)) {
+ lbx_errno = -errno;
+ if (img->fops->eof(img->f))
lbx_errno = LBX_EEOF;
- } else {
- lbx_errno = -errno;
- }
return -1;
}
if (img->currentframe != frame) {
int rc, first = 1;
- if (_lbx_fseek(img->f, &img->foff, img->offsets[frame]) == -1)
+ if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) {
+ lbx_errno = -errno;
return NULL;
+ }
do {
rc = _lbx_drawrow(first, img);
return NULL;
first = 0;
- if (!rc && img->foff > img->offsets[frame+1]) {
+ if (img->fops->tell(img->f) > img->offsets[frame+1]) {
lbx_errno = LBX_EFORMAT;
return NULL;
}
if (!(img->flags & FLAG_PALETTE))
return 0;
- if (_lbx_fseek(img->f, &img->foff, img->paloff) == -1)
+ if (img->fops->seek(img->f, img->paloff, SEEK_SET)) {
+ lbx_errno = -errno;
return -1;
+ }
for (i = 0; i < img->palcount; i++) {
- rc = fread(entry, 1, sizeof entry, img->f);
- img->foff += rc;
+ rc = img->fops->read(entry, sizeof entry, img->f);
if (rc < sizeof entry) {
goto readerr;
return 0;
readerr:
- lbx_errno = feof(img->f) ? LBX_EEOF : -errno;
+ lbx_errno = img->fops->eof(img->f) ? LBX_EEOF : -errno;
return -1;
}
return img->mask;
}
-void lbximg_close(struct lbx_image *img)
+int lbximg_close(struct lbx_image *img)
{
- if (!img) return;
+ int rc = 0;
- if (img->framedata) {
- free(img->framedata[0]);
- free(img->framedata);
- }
+ if (img) {
+ if (img->framedata) {
+ free(img->framedata[0]);
+ free(img->framedata);
+ }
- if (img->mask) {
- free(img->mask[0]);
- free(img->mask);
- }
+ if (img->mask) {
+ free(img->mask[0]);
+ free(img->mask);
+ }
+
+ if (img && img->dtor) {
+ rc = img->dtor(img->f);
+ }
- if (img->f) {
- fclose(img->f);
+ free(img);
}
- free(img);
+ return rc;
}
int main(int argc, char **argv)
{
- int mode = MODE_NONE;
- FILE *inf = stdin, *palf = NULL, *overf = NULL;
+ int mode = MODE_NONE, opt, rc = EXIT_FAILURE;
+ struct lbx_pipe_state state = { .f = stdin };
+ FILE *palf = NULL, *overf = NULL;
const char *name = "stdin";
LBX_IMG *img;
- int opt;
static const char *sopts = "idvf:p:O:V";
static const struct option lopts[] = {
name = strrchr(optarg, '/');
name = name ? name+1 : optarg;
- inf = fopen(optarg, "rb");
- if (!inf) {
+ if (!freopen(optarg, "rb", state.f)) {
errmsg("failed to open %s: %m\n", optarg);
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
- img = lbximg_fopen(inf);
+ if (fseek(state.f, 0, SEEK_CUR) == 0)
+ img = lbximg_open(state.f, &lbx_default_fops, NULL);
+ else
+ img = lbximg_open(&state, &lbx_pipe_fops, NULL);
+
if (!img) {
errmsg("failed to open image: %s.\n", lbx_strerror());
return EXIT_FAILURE;
switch (mode) {
case MODE_DECODE:
- if (decode(img, palf, overf, &argv[optind])) {
- lbximg_close(img);
- return EXIT_FAILURE;
- }
+ rc = decode(img, palf, overf, &argv[optind]);
break;
}
lbximg_close(img);
- return EXIT_SUCCESS;
+ return rc;
}
+++ /dev/null
-/*
- * 2ooM: The Master of Orion II Reverse Engineering Project
- * Miscellaneous common routines for liblbx.
- * 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 <http://www.gnu.org/licenses/>.
- */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-
-#include "misc.h"
-#include "lbx.h"
-
-int _lbx_fseek(FILE *f, long *current, size_t offset)
-{
- static unsigned char oblivion[1024];
- long dist;
-
- if (*current < offset) {
- dist = offset - *current;
- } else if (*current > offset) {
- dist = -(long)(*current - offset);
- } else {
- return 0;
- }
-
- if (fseek(f, dist, SEEK_CUR) == 0) {
- *current += dist;
- } else if (*current < offset) {
- while (dist) {
- size_t rc, amt = MIN(sizeof oblivion, dist);
- rc = fread(oblivion, 1, amt, f);
- *current += rc;
- dist -= rc;
- if (rc < amt) {
- if (feof(f))
- lbx_errno = LBX_EEOF;
- else
- lbx_errno = -errno;
- return -1;
- }
- }
- } else {
- lbx_errno = -errno;
- return -1;
- }
- return 0;
-}