]> git.imager.perl.org - imager.git/blobdiff - tga.c
add new comparison method rgb_difference that resembles arithmetical difference per...
[imager.git] / tga.c
diff --git a/tga.c b/tga.c
index 96e1f9444ce2817cf5e4c7c40d464fdcf70e5a82..8ee635a9121d73a19947c43d087b77ba9b469cb8 100644 (file)
--- a/tga.c
+++ b/tga.c
@@ -46,8 +46,8 @@ typedef struct {
   char  colourmapdepth;
   short int x_origin;
   short int y_origin;
-  short width;
-  short height;
+  int width;
+  int height;
   char  bitsperpixel;
   char  imagedescriptor;
 } tga_header;
@@ -57,7 +57,7 @@ typedef enum { NoInit, Raw, Rle } rle_state;
 
 typedef struct {
   int compressed;
-  int bytepp;
+  size_t bytepp;
   rle_state state;
   unsigned char cval[4];
   int len;
@@ -72,7 +72,7 @@ typedef struct {
   io_glue *ig;
 } tga_dest;
 
-
+#define TGA_MAX_DIM 0xFFFF
 
 /*
 =item bpp_to_bytes(bpp)
@@ -86,7 +86,7 @@ Convert bits per pixel into bytes per pixel
 
 
 static
-int
+size_t
 bpp_to_bytes(unsigned int bpp) {
   switch (bpp) {
   case 8:
@@ -433,7 +433,7 @@ int
 tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
   int cp = 0, j, k;
   if (!s->compressed) {
-    if (s->ig->readcb(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
+    if (i_io_read(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
     return 1;
   }
   
@@ -442,7 +442,7 @@ tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
     if (s->len == 0) s->state = NoInit;
     switch (s->state) {
     case NoInit:
-      if (s->ig->readcb(s->ig, &s->hdr, 1) != 1) return 0;
+      if (i_io_read(s->ig, &s->hdr, 1) != 1) return 0;
 
       s->len = (s->hdr &~(1<<7))+1;
       s->state = (s->hdr & (1<<7)) ? Rle : Raw;
@@ -452,7 +452,7 @@ tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
        printf("%04d %s: %d\n", cnt++, s->state==Rle?"RLE":"RAW", s->len);
  */
      }
-      if (s->state == Rle && s->ig->readcb(s->ig, s->cval, s->bytepp) != s->bytepp) return 0;
+      if (s->state == Rle && i_io_read(s->ig, s->cval, s->bytepp) != s->bytepp) return 0;
 
       break;
     case Rle:
@@ -464,7 +464,7 @@ tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
       break;
     case Raw:
       ml = i_min(s->len, pixels-cp);
-      if (s->ig->readcb(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0;
+      if (i_io_read(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0;
       cp     += ml;
       s->len -= ml;
       break;
@@ -495,7 +495,7 @@ tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
   int cp = 0;
 
   if (!s->compressed) {
-    if (s->ig->writecb(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
+    if (i_io_write(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
     return 1;
   }
   
@@ -506,9 +506,9 @@ tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
     while(tlen) {
       unsigned char clen = (tlen>128) ? 128 : tlen;
       clen--;
-      if (s->ig->writecb(s->ig, &clen, 1) != 1) return 0;
+      if (i_io_write(s->ig, &clen, 1) != 1) return 0;
       clen++;
-      if (s->ig->writecb(s->ig, buf+cp*s->bytepp, clen*s->bytepp) != clen*s->bytepp) return 0;
+      if (i_io_write(s->ig, buf+cp*s->bytepp, clen*s->bytepp) != clen*s->bytepp) return 0;
       tlen -= clen;
       cp += clen;
     }
@@ -518,9 +518,9 @@ tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
     while (tlen) {
       unsigned char clen = (tlen>128) ? 128 : tlen;
       clen = (clen - 1) | 0x80;
-      if (s->ig->writecb(s->ig, &clen, 1) != 1) return 0;
+      if (i_io_write(s->ig, &clen, 1) != 1) return 0;
       clen = (clen & ~0x80) + 1;
-      if (s->ig->writecb(s->ig, buf+cp*s->bytepp, s->bytepp) != s->bytepp) return 0;
+      if (i_io_write(s->ig, buf+cp*s->bytepp, s->bytepp) != s->bytepp) return 0;
       tlen -= clen;
       cp += clen;
     }
@@ -558,8 +558,8 @@ tga_palette_read(io_glue *ig, i_img *img, int bytepp, int colourmaplength) {
   palbsize = colourmaplength*bytepp;
   palbuf   = mymalloc(palbsize);
   
-  if (ig->readcb(ig, palbuf, palbsize) != palbsize) {
-    i_push_error(errno, "could not read targa colourmap");
+  if (i_io_read(ig, palbuf, palbsize) != palbsize) {
+    i_push_error(errno, "could not read targa colormap");
     return 0;
   }
   
@@ -590,7 +590,7 @@ static
 int
 tga_palette_write(io_glue *ig, i_img *img, int bitspp, int colourmaplength) {
   int i;
-  int bytepp = bpp_to_bytes(bitspp);
+  size_t bytepp = bpp_to_bytes(bitspp);
   size_t palbsize = i_colorcount(img)*bytepp;
   unsigned char *palbuf = mymalloc(palbsize);
   
@@ -600,8 +600,8 @@ tga_palette_write(io_glue *ig, i_img *img, int bitspp, int colourmaplength) {
     color_pack(palbuf+i*bytepp, bitspp, &val);
   }
   
-  if (ig->writecb(ig, palbuf, palbsize) != palbsize) {
-    i_push_error(errno, "could not write targa colourmap");
+  if (i_io_write(ig, palbuf, palbsize) != palbsize) {
+    i_push_error(errno, "could not write targa colormap");
     return 0;
   }
   myfree(palbuf);
@@ -641,9 +641,7 @@ i_readtga_wiol(io_glue *ig, int length) {
 
   mm_log((1,"i_readtga(ig %p, length %d)\n", ig, length));
   
-  io_glue_commit_types(ig);
-
-  if (ig->readcb(ig, &headbuf, 18) != 18) {
+  if (i_io_read(ig, &headbuf, 18) != 18) {
     i_push_error(errno, "could not read targa header");
     return NULL;
   }
@@ -664,8 +662,9 @@ i_readtga_wiol(io_glue *ig, int length) {
   mm_log((1,"Descriptor:        %d\n",header.imagedescriptor));
 
   if (header.idlength) {
+    /* max of 256, so this is safe */
     idstring = mymalloc(header.idlength+1);
-    if (ig->readcb(ig, idstring, header.idlength) != header.idlength) {
+    if (i_io_read(ig, idstring, header.idlength) != header.idlength) {
       i_push_error(errno, "short read on targa idstring");
       return NULL;
     }
@@ -724,8 +723,8 @@ i_readtga_wiol(io_glue *ig, int length) {
   
   mapped = 1;
   switch (header.datatypecode) {
-  case 2:  /* Uncompressed, rgb images          */
-  case 10: /* Compressed,   rgb images          */
+  case 2:  /* Uncompressed, rgb images          */ /* FALLTHROUGH */
+  case 10: /* Compressed,   rgb images          */ /* FALLTHROUGH */
     mapped = 0;
   case 1:  /* Uncompressed, color-mapped images */
   case 9:  /* Compressed,   color-mapped images */
@@ -737,7 +736,7 @@ i_readtga_wiol(io_glue *ig, int length) {
     if (idstring) myfree(idstring);
     return NULL;
     break;
-  case 3:  /* Uncompressed, grayscale images    */
+  case 3:  /* Uncompressed, grayscale images    */ /* FALLTHROUGH */
   case 11: /* Compressed,   grayscale images    */
     mapped = 0;
     channels = 1;
@@ -774,14 +773,15 @@ i_readtga_wiol(io_glue *ig, int length) {
                        bpp_to_bytes(header.colourmapdepth),
                        header.colourmaplength)
       ) {
-    i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
-    if (idstring) myfree(idstring);
+    /* tga_palette_read() sets a message */
     if (img) i_img_destroy(img);
     return NULL;
   }
   
   /* Allocate buffers */
+  /* width is max 0xffff, src.bytepp is max 4, so this is safe */
   databuf = mymalloc(width*src.bytepp);
+  /* similarly here */
   if (!mapped) linebuf = mymalloc(width*sizeof(i_color));
   
   for(y=0; y<height; y++) {
@@ -842,13 +842,17 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
   idlen = strlen(idstring);
   mapped = img->type == i_palette_type;
 
-  mm_log((1,"i_writetga_wiol(img %p, ig %p, idstring %p, idlen %d, wierdpack %d, compress %d)\n",
-         img, ig, idstring, idlen, wierdpack, compress));
+  mm_log((1,"i_writetga_wiol(img %p, ig %p, idstring %p, idlen %ld, wierdpack %d, compress %d)\n",
+         img, ig, idstring, (long)idlen, wierdpack, compress));
   mm_log((1, "virtual %d, paletted %d\n", img->virtual, mapped));
   mm_log((1, "channels %d\n", img->channels));
   
   i_clear_error();
-  io_glue_commit_types(ig);
+
+  if (img->xsize > TGA_MAX_DIM || img->ysize > TGA_MAX_DIM) {
+    i_push_error(0, "image too large for TGA");
+    return 0;
+  }
 
   switch (img->channels) {
   case 1:
@@ -891,13 +895,13 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
 
   tga_header_pack(&header, headbuf);
 
-  if (ig->writecb(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
+  if (i_io_write(ig, &headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
     i_push_error(errno, "could not write targa header");
     return 0;
   }
 
   if (idlen) {
-    if (ig->writecb(ig, idstring, idlen) != idlen) {
+    if (i_io_write(ig, idstring, idlen) != idlen) {
       i_push_error(errno, "could not write targa idstring");
       return 0;
     }
@@ -915,7 +919,7 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
     if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0;
     
     if (!img->virtual && !dest.compressed) {
-      if (ig->writecb(ig, img->idata, img->bytes) != img->bytes) {
+      if (i_io_write(ig, img->idata, img->bytes) != img->bytes) {
        i_push_error(errno, "could not write targa image data");
        return 0;
       }
@@ -930,8 +934,8 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
     }
   } else { /* direct type */
     int x, y;
-    int bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp);
-    int lsize = bytepp * img->xsize;
+    size_t bytepp = wierdpack ? 2 : bpp_to_bytes(bitspp);
+    size_t lsize = bytepp * img->xsize;
     i_color *vals = mymalloc(img->xsize*sizeof(i_color));
     unsigned char *buf = mymalloc(lsize);
     
@@ -944,7 +948,8 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
     myfree(vals);
   }
 
-  ig->closecb(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return 1;
 }