+ /* Read all offsets. Should be merged with identical code in lbx.c */
+ for (unsigned i = 0; i <= img->frames; 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;
+ free(img);
+ return NULL;
+ }
+
+ img->offsets[i] = unpack_32_le(buf);
+ }
+
+ if (img->flags & FLAG_PALETTE) {
+ unsigned char buf[4];
+
+ if (fops->read(buf, sizeof buf, f) != sizeof buf) {
+ lbx_errno = -errno;
+ 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->paloff = fops->tell(f);
+
+ if (img->palstart + img->palcount > 256) {
+ lbx_errno = LBX_EFORMAT;
+ free(img);
+ return NULL;
+ }
+ }
+
+ 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;
+ unsigned char buf[4];
+ unsigned char *pos;
+ size_t rc;
+
+ assert(img->framedata);
+ assert(img->mask);
+
+ if (img->fops->read(buf, sizeof buf, img->f) != sizeof buf)
+ goto readerr;
+ type = unpack_16_le(buf+0);
+
+ if (first) {
+ img->currentx = 0;
+ img->currenty = 0;
+ type = 0;
+ }
+
+ if (type == 0) {
+ yval = unpack_16_le(buf+2);
+ if (yval == 1000)
+ return 1;
+
+ if (img->fops->read(buf, sizeof buf, img->f) != sizeof buf)
+ goto readerr;
+ count = unpack_16_le(buf+0);
+
+ xval = unpack_16_le(buf+2);
+ if (xval == 1000)
+ return 1;
+
+ /* Ensure that the row fits in the image. */
+ if (img->height - img->currenty <= yval || xval >= img->width) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+
+ img->currenty += yval;
+ img->currentx = xval;
+ } else {
+ xval = unpack_16_le(buf+2);
+
+ if (img->width - img->currentx <= xval) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+ img->currentx += xval;
+
+ count = type;
+ }
+
+ if (count > img->width - img->currentx) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;