+ /* Start over if we are backtracking. */
+ if (img->currentframe > frame) {
+ memset(img->mask[0], 0, img->width * img->height);
+ img->currentframe = -1;
+ }
+
+ /* We must have previous frame decoded to continue. */
+ if (frame > img->currentframe + 1) {
+ if (!lbximg_getframe(img, frame-1))
+ return NULL;
+ }
+ }
+
+ if (img->currentframe != frame) {
+ int rc, first = 1;
+
+ if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) {
+ lbx_errno = -errno;
+ return NULL;
+ }
+
+ do {
+ rc = _lbx_drawrow(first, img);
+ if (rc == -1)
+ return NULL;
+ first = 0;
+
+ if (img->fops->tell(img->f) > img->offsets[frame+1]) {
+ lbx_errno = LBX_EFORMAT;
+ return NULL;
+ }
+ } while (!rc);
+ }
+
+ img->currentframe = frame;
+ return img->framedata;
+}
+
+int
+lbximg_loadpalette(void *f, const struct lbx_file_ops *fops,
+ struct lbx_colour palette[static 256])
+{
+ unsigned char entry[4];
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (fops->read(entry, sizeof entry, f) != sizeof entry) {
+ lbx_errno = (feof(f)) ? LBX_EEOF : -errno;
+ return -1;
+ }
+
+ if (entry[0] != 1) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+
+ palette[i] = (struct lbx_colour) {
+ .red = entry[1] << 2,
+ .green = entry[2] << 2,
+ .blue = entry[3] << 2,
+ .active = 1,
+ };
+ }
+
+ return 0;
+}
+
+int
+lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256])
+{
+ unsigned char entry[4];
+ unsigned int i;
+ size_t rc;
+
+ /* Do nothing if the image doesn't have embedded palette data. */
+ if (!(img->flags & FLAG_PALETTE))
+ return 0;
+
+ if (img->fops->seek(img->f, img->paloff, SEEK_SET)) {