- struct lbx_image tmp = {.f = f}, *new;
-
- if (fread(&tmp.width, sizeof tmp.width, 1, f) != 1) goto readerr;
- if (fread(&tmp.height, sizeof tmp.height, 1, f) != 1) goto readerr;
- if (fread(&tmp.wtf1, sizeof tmp.wtf1, 1, f) != 1) goto readerr;
- if (fread(&tmp.offs, sizeof tmp.offs, 1, f) != 1) goto readerr;
- if (fread(&tmp.frames, sizeof tmp.frames, 1, f) != 1) goto readerr;
- if (fread(&tmp.wtf2, sizeof tmp.wtf2, 1, f) != 1) goto readerr;
-
- tmp.width = letohs(tmp.width); tmp.foff += sizeof tmp.width;
- tmp.height = letohs(tmp.height); tmp.foff += sizeof tmp.height;
- tmp.wtf1 = letohs(tmp.wtf1); tmp.foff += sizeof tmp.wtf1;
- tmp.offs = letohs(tmp.offs); tmp.foff += sizeof tmp.offs;
- tmp.frames = letohs(tmp.frames); tmp.foff += sizeof tmp.frames;
- tmp.wtf2 = letohs(tmp.wtf2); tmp.foff += sizeof tmp.wtf2;
+ unsigned short nframes = unpack_16_le(hdr+6);
+ struct lbx_image_priv *img;
+
+ img = malloc(sizeof *img + sizeof img->offsets[0] * (nframes+1));
+ if (!img) {
+ lbx_error_raise(LBX_ENOMEM);
+ return NULL;
+ }
+
+ *img = (struct lbx_image_priv) {
+ .pub.width = unpack_16_le(hdr+0),
+ .pub.height = unpack_16_le(hdr+2),
+ .wtf = unpack_16_le(hdr+4),
+ .pub.frames = hdr[6],
+ .wtf2 = hdr[7],
+ .pub.leadin = hdr[8],
+ .pub.chunk = hdr[9],
+ .flags = unpack_16_le(hdr+10),
+ };
+
+ if (img->flags & FLAG_OVERWRITE)
+ img->pub.chunk = 1;
+
+ if (img->flags & FLAG_LOOPING)
+ img->pub.leadin = 0;
+
+ if (img->pub.leadin >= img->pub.frames) {
+ lbx_error_raise(LBX_EFORMAT);
+ free(img);
+ return NULL;
+ }
+
+ return img;
+}
+
+struct lbx_image *lbx_img_open(void *f, const struct lbx_file_ops *fops,
+ int (*destructor)(void *))
+{
+ unsigned char hdr_buf[HDR_LEN];
+ struct lbx_image_priv *img;
+
+ if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) {
+ if (fops->eof(f))
+ lbx_error_raise(LBX_EEOF);
+ return NULL;
+ }
+
+ img = lbx_img_init(hdr_buf);
+ if (!img)
+ return NULL;
+
+ img->f = f;
+ img->fops = fops;
+ img->dtor = destructor;