]> git.draconx.ca Git - liblbx.git/commitdiff
Starting implementation of image parsing code.
authorNick Bowler <draconx@gmail.com>
Sun, 30 Dec 2007 06:03:02 +0000 (01:03 -0500)
committerNick Bowler <draconx@gmail.com>
Mon, 31 Dec 2007 01:42:15 +0000 (20:42 -0500)
src/image.c
src/image.h
src/lbx.c
src/lbx.h

index 86f6f98f829a029b3a4a0235f007b546d7c25465..a5b8b058557cc6f6179d27477eb1abd3cf2346b0 100644 (file)
@@ -7,14 +7,23 @@
 #include <assert.h>
 #include <errno.h>
 
-#include "lbx.h"
 #include "byteorder.h"
+#include "misc.h"
+#include "lbx.h"
+#include "image.h"
 
 struct lbx_image {
-       FILE *f;
        uint16_t width, height;
        uint16_t wtf1, wtf2;
        uint16_t offs, frames;
+
+       FILE *f;
+       long foff;
+
+       int currentframe;
+       int currentx, currenty;
+       unsigned char **framedata;
+
        uint32_t offsets[];
 };
 
@@ -29,12 +38,12 @@ struct lbx_image *lbximg_fopen(FILE *f)
        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.height = letohs(tmp.height);
-       tmp.wtf1   = letohs(tmp.wtf1);
-       tmp.offs   = letohs(tmp.offs);
-       tmp.frames = letohs(tmp.frames);
-       tmp.wtf2   = letohs(tmp.wtf2);
+       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;
 
        /*
         * DEBUG ONLY.  These assertions exist to catch otherwise valid image
@@ -52,9 +61,11 @@ struct lbx_image *lbximg_fopen(FILE *f)
        }
 
        *new = tmp;
+       new->currentframe = -1;
 
-       if (fread(new->offsets, sizeof *new->offsets, new->offs, f) != new->offs)
+       if (fread(new->offsets, sizeof *new->offsets, new->offs, f)!= new->offs)
                goto readerr;
+       new->foff += sizeof *new->offsets * new->offs;
 
        return new;
 readerr:
@@ -68,10 +79,151 @@ readerr:
        return NULL;
 }
 
+static int _lbx_drawrow(int first, struct lbx_image *img)
+{
+       uint16_t type, yval, count, xval;
+       unsigned char *pos;
+       unsigned char abyss;
+       size_t rc;
+
+       assert(img->framedata);
+
+       if (fread(&type, sizeof type, 1, img->f) != 1) goto readerr;
+       type = letohs(type); img->foff += sizeof type;
+
+       if (first) {
+               img->currentx = 0;
+               img->currenty = 0;
+               type = 0;
+       }
+
+       if (type == 0) {
+               if (fread(&yval,  sizeof yval,  1, img->f) != 1) goto readerr;
+               yval = letohs(yval); img->foff += sizeof yval;
+
+               if (yval == 1000)
+                       return 1;
+
+               if (fread(&count, sizeof count, 1, img->f) != 1) goto readerr;
+               count = letohs(count); img->foff += sizeof count;
+               if (fread(&xval,  sizeof xval,  1, img->f) != 1) goto readerr;
+               xval = letohs(xval); img->foff += sizeof xval;
+
+               /* Ensure that the row fits in the image. */
+               if (img->height - img->currenty <= yval
+                   || xval >= img->width || count > img->width - xval) {
+                       lbx_errno = LBX_EFORMAT;
+                       return -1;
+               }
+
+               img->currenty += yval;
+               img->currentx  = xval;
+       } else {
+               count = 0;
+/*
+               count = type;
+               if (count > img->width - img->currentx) {
+                       lbx_errno = LBX_EFORMAT;
+                       return -1;
+               }
+*/
+       }
+
+       pos = &img->framedata[img->currenty][img->currentx];
+       rc  = fread(pos, 1, count, img->f);
+       img->currentx += rc;
+       img->foff     += rc;
+
+       if (rc < count)
+               goto readerr;
+
+       if (count % 2) {
+               if (fread(&abyss, 1, 1, img->f) != 1)
+                       goto readerr;
+               img->foff += 1;
+       }
+
+       return 0;
+readerr:
+       if (feof(img->f)) {
+               lbx_errno = LBX_EEOF;
+       } else {
+               lbx_errno = -errno;
+       }
+       return -1;
+}
+
+unsigned char **lbximg_getframe(struct lbx_image *img, int frame)
+{
+       if (frame >= img->frames || frame < 0) {
+               lbx_errno = LBX_ERANGE;
+               return NULL;
+       }
+
+       if (!img->framedata) {
+               unsigned char *tmp;
+               int i;
+
+               tmp = malloc(img->width * img->height);
+               if (!tmp) {
+                       lbx_errno = -errno;
+                       return NULL;
+               }
+
+               img->framedata = malloc(img->height * sizeof *img->framedata);
+               if (!img->framedata) {
+                       lbx_errno = -errno;
+                       free(tmp);
+                       return NULL;
+               }
+
+               for (i = 0; i < img->height; i++) {
+                       img->framedata[i] = tmp + i * img->width;
+               }
+       }
+
+       /* Start over if we are backtracking. */
+       if (img->currentframe > frame)
+               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 (_lbx_fseek(img->f, &img->foff, img->offsets[frame]) == -1)
+                       return NULL;
+
+               do {
+                       rc = _lbx_drawrow(first, img);
+                       if (rc == -1)
+                               return NULL;
+                       first = 0;
+
+                       if (img->foff > img->offsets[frame+1]) {
+                               lbx_errno = LBX_EFORMAT;
+                               return NULL;
+                       }
+               } while (!rc);
+       }
+
+       img->currentframe = frame;
+       return img->framedata;
+}
+
 void lbximg_close(struct lbx_image *img)
 {
        if (!img) return;
 
+       if (img->framedata) {
+               free(img->framedata[0]);
+               free(img->framedata);
+       }
+
        if (img->f) {
                fclose(img->f);
        }
index 5b5e4a362dd9aebbe39c41709a29592462d94b71..e9de2bdbbb4411e4e78b571a758c6270ac69b1b9 100644 (file)
@@ -7,5 +7,6 @@ typedef struct lbx_image LBXIMG;
 
 LBXIMG *lbximg_fopen(FILE *f);
 void    lbximg_close(LBXIMG *img);
+unsigned char **lbximg_getframe(LBXIMG *img, int frame);
 
 #endif
index d3815a92e2a382acef57e7fd41ddb4cc5a2d1f8f..3f947c1be269169970866b5a6be4e515a954f5c1 100644 (file)
--- a/src/lbx.c
+++ b/src/lbx.c
@@ -292,6 +292,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";
index ec525d0bf56eee05b6fa12eee283b43d8e0ea09b..a2ca456f949eb72dbaa81dc5c00d4d173bf6287c 100644 (file)
--- a/src/lbx.h
+++ b/src/lbx.h
@@ -9,6 +9,7 @@ enum {
        LBX_EMAGIC,
        LBX_EEOF,
        LBX_ERANGE,
+       LBX_EFORMAT,
 };
 extern int lbx_errno;