avoid a possible sign-extension for offsets/sizes in SGI
[imager.git] / SGI / imsgi.c
index 54a2d49..f6ad1b5 100644 (file)
@@ -20,6 +20,9 @@
 /* we add that little bit to avoid rounding issues */
 #define SampleFTo16(num) ((int)((num) * 65535.0 + 0.01))
 
+/* maximum size of an SGI image */
+#define SGI_DIM_LIMIT 0xFFFF
+
 typedef struct {
   unsigned short imagic;
   unsigned char storagetype;
@@ -121,7 +124,7 @@ store_16(unsigned char *buf, unsigned short value) {
 }
 
 static void
-store_32(unsigned char *buf, unsigned short value) {
+store_32(unsigned char *buf, unsigned long value) {
   buf[0] = value >> 24;
   buf[1] = (value >> 16) & 0xFF;
   buf[2] = (value >> 8) & 0xFF;
@@ -179,7 +182,7 @@ i_readsgi_wiol(io_glue *ig, int partial) {
   mm_log((1,"i_readsgi(ig %p, partial %d)\n", ig, partial));
   i_clear_error();
 
-  if (ig->readcb(ig, headbuf, 512) != 512) {
+  if (i_io_read(ig, headbuf, 512) != 512) {
     i_push_error(errno, "SGI image: could not read header");
     return NULL;
   }
@@ -325,6 +328,11 @@ i_writesgi_wiol(io_glue *ig, i_img *img) {
 
   i_clear_error();
 
+  if (img->xsize > SGI_DIM_LIMIT || img->ysize > SGI_DIM_LIMIT) {
+    i_push_error(0, "image too large for SGI");
+    return 0;
+  }
+
   if (!write_sgi_header(img, ig, &rle, &bpc2))
     return 0;
 
@@ -367,7 +375,7 @@ read_rgb_8_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
     for(y = 0; y < height; y++) {
       int x;
       
-      if (ig->readcb(ig, databuf, width) != width) {
+      if (i_io_read(ig, databuf, width) != width) {
        i_push_error(0, "SGI image: cannot read image data");
        i_img_destroy(img);
        myfree(linebuf);
@@ -428,32 +436,32 @@ read_rle_tables(io_glue *ig, i_img *img,
   length_tab = mymalloc(height*channels*sizeof(unsigned long));
     
     /* Read offset table */
-  if (ig->readcb(ig, databuf, height * channels * 4) != height * channels * 4) {
+  if (i_io_read(ig, databuf, height * channels * 4) != height * channels * 4) {
     i_push_error(0, "SGI image: short read reading RLE start table");
     goto ErrorReturn;
   }
 
   for(i = 0; i < height * channels; i++) 
-    start_tab[i] = (databuf[i*4] << 24) | (databuf[i*4+1] << 16) | 
+    start_tab[i] = ((unsigned long)databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
       (databuf[i*4+2] << 8) | (databuf[i*4+3]);
 
 
   /* Read length table */
-  if (ig->readcb(ig, databuf, height*channels*4) != height*channels*4) {
+  if (i_io_read(ig, databuf, height*channels*4) != height*channels*4) {
     i_push_error(0, "SGI image: short read reading RLE length table");
     goto ErrorReturn;
   }
 
   for(i=0; i < height * channels; i++) {
-    length_tab[i] = (databuf[i*4] << 24) + (databuf[i*4+1] << 16)+
-      (databuf[i*4+2] << 8) + (databuf[i*4+3]);
+    length_tab[i] = ((unsigned long)databuf[i*4] << 24) | (databuf[i*4+1] << 16) |
+      (databuf[i*4+2] << 8) | (databuf[i*4+3]);
     if (length_tab[i] > max_length)
       max_length = length_tab[i];
   }
 
   mm_log((3, "Offset/length table:\n"));
   for(i=0; i < height * channels; i++)
-    mm_log((3, "%d: %d/%d\n", i, start_tab[i], length_tab[i]));
+    mm_log((3, "%d: %lu/%lu\n", i, start_tab[i], length_tab[i]));
 
   *pstart_tab = start_tab;
   *plength_tab = length_tab;
@@ -492,7 +500,7 @@ read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) {
     return NULL;
   }
 
-  mm_log((1, "maxlen for an rle buffer: %d\n", max_length));
+  mm_log((1, "maxlen for an rle buffer: %lu\n", max_length));
 
   if (max_length > (img->xsize + 1) * 2) {
     i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
@@ -512,11 +520,11 @@ read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) {
       int pixels_left = width;
       i_sample_t sample;
       
-      if (ig->seekcb(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
+      if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
        i_push_error(0, "SGI image: cannot seek to RLE data");
        goto ErrorReturn;
       }
-      if (ig->readcb(ig, databuf, datalen) != datalen) {
+      if (i_io_read(ig, databuf, datalen) != datalen) {
        i_push_error(0, "SGI image: cannot read RLE data");
        goto ErrorReturn;
       }
@@ -568,7 +576,7 @@ read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) {
          /* RLE run */
          if (count > pixels_left) {
            i_push_error(0, "SGI image: RLE run overflows scanline");
-           mm_log((2, "RLE run overflows scanline (y %d chan %d offset %ld len %ld)\n", y, c, start_tab[ci], length_tab[ci]));
+           mm_log((2, "RLE run overflows scanline (y %" i_DF " chan %d offset %lu len %lu)\n", i_DFc(y), c, start_tab[ci], length_tab[ci]));
            goto ErrorReturn;
          }
          if (data_left < 1) {
@@ -648,7 +656,7 @@ read_rgb_16_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
     for(y = 0; y < height; y++) {
       int x;
       
-      if (ig->readcb(ig, databuf, width*2) != width*2) {
+      if (i_io_read(ig, databuf, width*2) != width*2) {
        i_push_error(0, "SGI image: cannot read image data");
        i_img_destroy(img);
        myfree(linebuf);
@@ -730,11 +738,11 @@ read_rgb_16_rle(i_img *img, io_glue *ig, rgb_header const *header) {
        i_push_error(0, "SGI image: invalid RLE length value for BPC=2");
        goto ErrorReturn;
       }
-      if (ig->seekcb(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
+      if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
        i_push_error(0, "SGI image: cannot seek to RLE data");
        goto ErrorReturn;
       }
-      if (ig->readcb(ig, databuf, datalen) != datalen) {
+      if (i_io_read(ig, databuf, datalen) != datalen) {
        i_push_error(0, "SGI image: cannot read RLE data");
        goto ErrorReturn;
       }
@@ -904,7 +912,7 @@ write_sgi_8_verb(i_img *img, io_glue *ig) {
   for (c = 0; c < img->channels; ++c) {
     for (y = img->ysize - 1; y >= 0; --y) {
       i_gsamp(img, 0, width, y, linebuf, &c, 1);
-      if (ig->writecb(ig, linebuf, width) != width) {
+      if (i_io_write(ig, linebuf, width) != width) {
        i_push_error(errno, "SGI image: error writing image data");
        myfree(linebuf);
        return 0;
@@ -913,6 +921,9 @@ write_sgi_8_verb(i_img *img, io_glue *ig) {
   }
   myfree(linebuf);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 }
 
@@ -987,9 +998,8 @@ write_sgi_8_rle(i_img *img, io_glue *ig) {
          
          /* fill out the run if 2 or less samples left and there's space */
          if (in_left - run_length <= 2 
-             && run_length + in_left - run_length <= 127) {
-           run_length += in_left;
-           in_left = 0;
+             && in_left <= 127) {
+           run_length = in_left;
          }
          in_left -= run_length;
          *outp++ = run_length | 0x80;
@@ -1004,7 +1014,7 @@ write_sgi_8_rle(i_img *img, io_glue *ig) {
       store_32(lengths + offset_pos, comp_size);
       offset_pos += 4;
       current_offset += comp_size;
-      if (ig->writecb(ig, comp_buf, comp_size) != comp_size) {
+      if (i_io_write(ig, comp_buf, comp_size) != comp_size) {
        i_push_error(errno, "SGI image: error writing RLE data");
        goto Error;
       }
@@ -1026,6 +1036,9 @@ write_sgi_8_rle(i_img *img, io_glue *ig) {
   myfree(comp_buf);
   myfree(linebuf);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 
  Error:
@@ -1054,7 +1067,7 @@ write_sgi_16_verb(i_img *img, io_glue *ig) {
        unsigned short samp16 = SampleFTo16(linebuf[x]);
        store_16(outp, samp16);
       }
-      if (ig->writecb(ig, encbuf, width * 2) != width * 2) {
+      if (i_io_write(ig, encbuf, width * 2) != width * 2) {
        i_push_error(errno, "SGI image: error writing image data");
        myfree(linebuf);
        myfree(encbuf);
@@ -1065,6 +1078,9 @@ write_sgi_16_verb(i_img *img, io_glue *ig) {
   myfree(linebuf);
   myfree(encbuf);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 }
 
@@ -1145,9 +1161,8 @@ write_sgi_16_rle(i_img *img, io_glue *ig) {
          
          /* fill out the run if 2 or less samples left and there's space */
          if (in_left - run_length <= 2 
-             && run_length + in_left - run_length <= 127) {
-           run_length += in_left;
-           in_left = 0;
+             && in_left <= 127) {
+           run_length = in_left;
          }
          in_left -= run_length;
          store_16(outp, run_length | 0x80);
@@ -1165,7 +1180,7 @@ write_sgi_16_rle(i_img *img, io_glue *ig) {
       store_32(lengths + offset_pos, comp_size);
       offset_pos += 4;
       current_offset += comp_size;
-      if (ig->writecb(ig, comp_buf, comp_size) != comp_size) {
+      if (i_io_write(ig, comp_buf, comp_size) != comp_size) {
        i_push_error(errno, "SGI image: error writing RLE data");
        goto Error;
       }
@@ -1188,6 +1203,9 @@ write_sgi_16_rle(i_img *img, io_glue *ig) {
   myfree(linebuf);
   myfree(sampbuf);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 
  Error: