fix a fence post error validating a combing mode number
[imager.git] / SGI / imsgi.c
1 #include "imsgi.h"
2
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <string.h>
6
7 /* value for imagic */
8 #define SGI_MAGIC 474
9
10 /* values for the storage field */
11 #define SGI_STORAGE_VERBATIM 0
12 #define SGI_STORAGE_RLE 1
13
14 /* values for the colormap field */
15 #define SGI_COLORMAP_NORMAL 0
16 #define SGI_COLORMAP_DITHERED 1
17 #define SGI_COLORMAP_SCREEN 2
18 #define SGI_COLORMAP_COLORMAP 3
19
20 /* we add that little bit to avoid rounding issues */
21 #define SampleFTo16(num) ((int)((num) * 65535.0 + 0.01))
22
23 /* maximum size of an SGI image */
24 #define SGI_DIM_LIMIT 0xFFFF
25
26 typedef struct {
27   unsigned short imagic;
28   unsigned char storagetype;
29   unsigned char BPC;
30   unsigned short dimensions;
31   unsigned short xsize, ysize, zsize;
32   unsigned int pixmin, pixmax;
33   char name[80];
34   unsigned int colormap;
35 } rgb_header;
36
37 static i_img *
38 read_rgb_8_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr);
39 static i_img *
40 read_rgb_8_rle(i_img *im, io_glue *ig, rgb_header const *hdr);
41 static i_img *
42 read_rgb_16_verbatim(i_img *im, io_glue *ig, rgb_header const *hdr);
43 static i_img *
44 read_rgb_16_rle(i_img *im, io_glue *ig, rgb_header const *hdr);
45 static int
46 write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2);
47 static int
48 write_sgi_8_rle(i_img *img, io_glue *ig);
49 static int
50 write_sgi_8_verb(i_img *img, io_glue *ig);
51 static int
52 write_sgi_16_rle(i_img *img, io_glue *ig);
53 static int
54 write_sgi_16_verb(i_img *img, io_glue *ig);
55
56 #define Sample16ToF(num) ((num) / 65535.0)
57
58 #define _STRING(x) #x
59 #define STRING(x) _STRING(x)
60
61 /*
62 =head1 NAME
63
64 rgb.c - implements reading and writing sgi image files, uses io layer.
65
66 =head1 SYNOPSIS
67
68    io_glue *ig = io_new_fd( fd );
69    i_img *im   = i_readrgb_wiol(ig, 0); // disallow partial reads
70    // or 
71    io_glue *ig = io_new_fd( fd );
72    return_code = i_writergb_wiol(im, ig); 
73
74 =head1 DESCRIPTION
75
76 imsgi.c implements the basic functions to read and write portable SGI
77 files.  It uses the iolayer and needs either a seekable source or an
78 entire memory mapped buffer.
79
80 =head1 FUNCTION REFERENCE
81
82 Some of these functions are internal.
83
84 =over
85
86 =cut
87 */
88
89 /*
90 =item rgb_header_unpack(header, headbuf)
91
92 Unpacks the header structure into from buffer and stores
93 in the header structure.
94
95     header - header structure
96     headbuf - buffer to unpack from
97
98 =cut
99 */
100
101
102 static
103 void
104 rgb_header_unpack(rgb_header *header, const unsigned char *headbuf) {
105   header->imagic      = (headbuf[0]<<8) + headbuf[1];
106   header->storagetype = headbuf[2];
107   header->BPC         = headbuf[3];
108   header->dimensions  = (headbuf[4]<<8) + headbuf[5];
109   header->xsize       = (headbuf[6]<<8) + headbuf[7];
110   header->ysize       = (headbuf[8]<<8) + headbuf[9];
111   header->zsize       = (headbuf[10]<<8) + headbuf[11];
112   header->pixmin      = (headbuf[12]<<24) + (headbuf[13]<<16)+(headbuf[14]<<8)+headbuf[15];
113   header->pixmax      = (headbuf[16]<<24) + (headbuf[17]<<16)+(headbuf[18]<<8)+headbuf[19];
114   memcpy(header->name,headbuf+24,80);
115   header->name[79] = '\0';
116   header->colormap    = (headbuf[104]<<24) + (headbuf[105]<<16)+(headbuf[106]<<8)+headbuf[107];
117 }
118
119 /* don't make this a macro */
120 static void
121 store_16(unsigned char *buf, unsigned short value) {
122   buf[0] = value >> 8;
123   buf[1] = value & 0xFF;
124 }
125
126 static void
127 store_32(unsigned char *buf, unsigned long value) {
128   buf[0] = value >> 24;
129   buf[1] = (value >> 16) & 0xFF;
130   buf[2] = (value >> 8) & 0xFF;
131   buf[3] = value & 0xFF;
132 }
133
134 /*
135 =item rgb_header_pack(header, headbuf)
136
137 Packs header structure into buffer for writing.
138
139     header - header structure
140     headbuf - buffer to pack into
141
142 =cut
143 */
144
145 static
146 void
147 rgb_header_pack(const rgb_header *header, unsigned char headbuf[512]) {
148   memset(headbuf, 0, 512);
149   store_16(headbuf, header->imagic);
150   headbuf[2] = header->storagetype;
151   headbuf[3] = header->BPC;
152   store_16(headbuf+4, header->dimensions);
153   store_16(headbuf+6, header->xsize);
154   store_16(headbuf+8, header->ysize);
155   store_16(headbuf+10, header->zsize);
156   store_32(headbuf+12, header->pixmin);
157   store_32(headbuf+16, header->pixmax);
158   memccpy(headbuf+24, header->name, '\0', 80);
159   store_32(headbuf+104, header->colormap);
160 }
161
162 /*
163 =item i_readsgi_wiol(ig, partial)
164
165 Read in an image from the iolayer data source and return the image structure to it.
166 Returns NULL on error.
167
168    ig     - io_glue object
169    length - maximum length to read from data source, before closing it -1 
170             signifies no limit.
171
172 =cut
173 */
174
175 i_img *
176 i_readsgi_wiol(io_glue *ig, int partial) {
177   i_img *img = NULL;
178   int width, height, channels;
179   rgb_header header;
180   unsigned char headbuf[512];
181
182   mm_log((1,"i_readsgi(ig %p, partial %d)\n", ig, partial));
183   i_clear_error();
184
185   if (i_io_read(ig, headbuf, 512) != 512) {
186     i_push_error(errno, "SGI image: could not read header");
187     return NULL;
188   }
189
190   rgb_header_unpack(&header, headbuf);
191
192   if (header.imagic != SGI_MAGIC) {
193     i_push_error(0, "SGI image: invalid magic number");
194     return NULL;
195   }
196
197   mm_log((1,"imagic:         %d\n", header.imagic));
198   mm_log((1,"storagetype:    %d\n", header.storagetype));
199   mm_log((1,"BPC:            %d\n", header.BPC));
200   mm_log((1,"dimensions:     %d\n", header.dimensions));
201   mm_log((1,"xsize:          %d\n", header.xsize));
202   mm_log((1,"ysize:          %d\n", header.ysize));
203   mm_log((1,"zsize:          %d\n", header.zsize));
204   mm_log((1,"min:            %d\n", header.pixmin));
205   mm_log((1,"max:            %d\n", header.pixmax));
206   mm_log((1,"name [skipped]\n"));
207   mm_log((1,"colormap:       %d\n", header.colormap));
208
209   if (header.colormap != SGI_COLORMAP_NORMAL) {
210     i_push_errorf(0, "SGI image: invalid value for colormap (%d)", header.colormap);
211     return NULL;
212   }
213
214   if (header.BPC != 1 && header.BPC != 2) {
215     i_push_errorf(0, "SGI image: invalid value for BPC (%d)", header.BPC);
216     return NULL;
217   }
218
219   if (header.storagetype != SGI_STORAGE_VERBATIM 
220       && header.storagetype != SGI_STORAGE_RLE) {
221     i_push_error(0, "SGI image: invalid storage type field");
222     return NULL;
223   }
224
225   if (header.pixmin >= header.pixmax) {
226     i_push_error(0, "SGI image: invalid pixmin >= pixmax");
227     return NULL;
228   }
229
230   width    = header.xsize;
231   height   = header.ysize;
232   channels = header.zsize;
233
234   switch (header.dimensions) {
235   case 1:
236     channels = 1;
237     height = 1;
238     break;
239
240   case 2:
241     channels = 1;
242     break;
243
244   case 3:
245     /* fall through and use all of the dimensions */
246     break;
247
248   default:
249     i_push_error(0, "SGI image: invalid dimension field");
250     return NULL;
251   }
252
253   if (!i_int_check_image_file_limits(width, height, channels, header.BPC)) {
254     mm_log((1, "i_readsgi_wiol: image size exceeds limits\n"));
255     return NULL;
256   }
257
258   if (header.BPC == 1) {
259     img = i_img_8_new(width, height, channels);
260     if (!img)
261       goto ErrorReturn;
262
263     switch (header.storagetype) {
264     case SGI_STORAGE_VERBATIM:
265       img = read_rgb_8_verbatim(img, ig, &header);
266       break;
267
268     case SGI_STORAGE_RLE:
269       img = read_rgb_8_rle(img, ig, &header);
270       break;
271
272     default:
273       goto ErrorReturn;
274     }
275   }
276   else {
277     img = i_img_16_new(width, height, channels);
278     if (!img)
279       goto ErrorReturn;
280
281     switch (header.storagetype) {
282     case SGI_STORAGE_VERBATIM:
283       img = read_rgb_16_verbatim(img, ig, &header);
284       break;
285
286     case SGI_STORAGE_RLE:
287       img = read_rgb_16_rle(img, ig, &header);
288       break;
289
290     default:
291       goto ErrorReturn;
292     }
293   }
294
295   if (!img)
296     goto ErrorReturn;
297
298   if (*header.name)
299     i_tags_set(&img->tags, "i_comment", header.name, -1);
300   i_tags_setn(&img->tags, "sgi_pixmin", header.pixmin);
301   i_tags_setn(&img->tags, "sgi_pixmax", header.pixmax);
302   i_tags_setn(&img->tags, "sgi_bpc", header.BPC);
303   i_tags_setn(&img->tags, "sgi_rle", header.storagetype == SGI_STORAGE_RLE);
304   i_tags_set(&img->tags, "i_format", "sgi", -1);
305
306   return img;
307
308  ErrorReturn:
309   if (img) i_img_destroy(img);
310   return NULL;
311 }
312
313 /*
314 =item i_writergb_wiol(img, ig)
315
316 Writes an image in targa format.  Returns 0 on error.
317
318    img    - image to store
319    ig     - io_glue object
320
321 =cut
322 */
323
324 int
325 i_writesgi_wiol(io_glue *ig, i_img *img) {
326   int rle;
327   int bpc2;
328
329   i_clear_error();
330
331   if (img->xsize > SGI_DIM_LIMIT || img->ysize > SGI_DIM_LIMIT) {
332     i_push_error(0, "image too large for SGI");
333     return 0;
334   }
335
336   if (!write_sgi_header(img, ig, &rle, &bpc2))
337     return 0;
338
339   mm_log((1, "format rle %d bpc2 %d\n", rle, bpc2));
340
341   if (bpc2) {
342     if (rle)
343       return write_sgi_16_rle(img, ig);
344     else
345       return write_sgi_16_verb(img, ig);
346   }
347   else {
348     if (rle)
349       return write_sgi_8_rle(img, ig);
350     else
351       return write_sgi_8_verb(img, ig);
352   }
353 }
354
355 static i_img *
356 read_rgb_8_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
357   i_color *linebuf;
358   unsigned char *databuf;
359   int c, y;
360   int savemask;
361   i_img_dim width = i_img_get_width(img);
362   i_img_dim height = i_img_get_height(img);
363   int channels = i_img_getchannels(img);
364   int pixmin = header->pixmin;
365   int pixmax = header->pixmax;
366   int outmax = pixmax - pixmin;
367   
368   linebuf   = mymalloc(width * sizeof(i_color)); /* checked 31Jul07 TonyC */
369   databuf   = mymalloc(width); /* checked 31Jul07 TonyC */
370
371   savemask = i_img_getmask(img);
372
373   for(c = 0; c < channels; c++) {
374     i_img_setmask(img, 1<<c);
375     for(y = 0; y < height; y++) {
376       int x;
377       
378       if (i_io_read(ig, databuf, width) != width) {
379         i_push_error(0, "SGI image: cannot read image data");
380         i_img_destroy(img);
381         myfree(linebuf);
382         myfree(databuf);
383         return NULL;
384       }
385
386       if (pixmin == 0 && pixmax == 255) {
387         for(x = 0; x < img->xsize; x++)
388           linebuf[x].channel[c] = databuf[x];
389       }
390       else {
391         for(x = 0; x < img->xsize; x++) {
392           int sample = databuf[x];
393           if (sample < pixmin)
394             sample = 0;
395           else if (sample > pixmax)
396             sample = outmax;
397           else
398             sample -= pixmin;
399             
400           linebuf[x].channel[c] = sample * 255 / outmax;
401         }
402       }
403       
404       i_plin(img, 0, width, height-1-y, linebuf);
405     }
406   }
407   i_img_setmask(img, savemask);
408
409   myfree(linebuf);
410   myfree(databuf);
411   
412   return img;
413 }
414
415 static int
416 read_rle_tables(io_glue *ig, i_img *img,
417                 unsigned long **pstart_tab, unsigned long **plength_tab, 
418                 unsigned long *pmax_length) {
419   i_img_dim height = i_img_get_height(img);
420   int channels = i_img_getchannels(img);
421   unsigned char *databuf;
422   unsigned long *start_tab, *length_tab;
423   unsigned long max_length = 0;
424   int i;
425   size_t databuf_size = (size_t)height * channels * 4;
426   size_t tab_size = (size_t)height * channels * sizeof(unsigned long);
427
428   /* assumption: that the lengths are in bytes rather than in pixels */
429   if (databuf_size / height / channels != 4
430       || tab_size / height / channels != sizeof(unsigned long)) {
431     i_push_error(0, "SGI image: integer overflow calculating allocation size");
432     return 0;
433   }
434   databuf    = mymalloc(height * channels * 4);  /* checked 31Jul07 TonyC */
435   start_tab  = mymalloc(height*channels*sizeof(unsigned long));
436   length_tab = mymalloc(height*channels*sizeof(unsigned long));
437     
438     /* Read offset table */
439   if (i_io_read(ig, databuf, height * channels * 4) != height * channels * 4) {
440     i_push_error(0, "SGI image: short read reading RLE start table");
441     goto ErrorReturn;
442   }
443
444   for(i = 0; i < height * channels; i++) 
445     start_tab[i] = (databuf[i*4] << 24) | (databuf[i*4+1] << 16) | 
446       (databuf[i*4+2] << 8) | (databuf[i*4+3]);
447
448
449   /* Read length table */
450   if (i_io_read(ig, databuf, height*channels*4) != height*channels*4) {
451     i_push_error(0, "SGI image: short read reading RLE length table");
452     goto ErrorReturn;
453   }
454
455   for(i=0; i < height * channels; i++) {
456     length_tab[i] = (databuf[i*4] << 24) + (databuf[i*4+1] << 16)+
457       (databuf[i*4+2] << 8) + (databuf[i*4+3]);
458     if (length_tab[i] > max_length)
459       max_length = length_tab[i];
460   }
461
462   mm_log((3, "Offset/length table:\n"));
463   for(i=0; i < height * channels; i++)
464     mm_log((3, "%d: %lu/%lu\n", i, start_tab[i], length_tab[i]));
465
466   *pstart_tab = start_tab;
467   *plength_tab = length_tab;
468   *pmax_length = max_length;
469
470   myfree(databuf);
471
472   return 1;
473
474  ErrorReturn:
475   myfree(databuf);
476   myfree(start_tab);
477   myfree(length_tab);
478
479   return 0;
480 }
481
482 static i_img *
483 read_rgb_8_rle(i_img *img, io_glue *ig, rgb_header const *header) {
484   i_color *linebuf = NULL;
485   unsigned char *databuf = NULL;
486   unsigned long *start_tab, *length_tab;
487   unsigned long max_length;
488   i_img_dim width = i_img_get_width(img);
489   i_img_dim height = i_img_get_height(img);
490   int channels = i_img_getchannels(img);
491   i_img_dim y;
492   int c;
493   int pixmin = header->pixmin;
494   int pixmax = header->pixmax;
495   int outmax = pixmax - pixmin;
496
497   if (!read_rle_tables(ig, img,  
498                        &start_tab, &length_tab, &max_length)) {
499     i_img_destroy(img);
500     return NULL;
501   }
502
503   mm_log((1, "maxlen for an rle buffer: %lu\n", max_length));
504
505   if (max_length > (img->xsize + 1) * 2) {
506     i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
507     goto ErrorReturn;
508   }
509
510   linebuf = mymalloc(width*sizeof(i_color)); /* checked 31Jul07 TonyC */
511   databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */
512
513   for(y = 0; y < img->ysize; y++) {
514     for(c = 0; c < channels; c++) {
515       int ci = height * c + y;
516       int datalen = length_tab[ci];
517       unsigned char *inp;
518       i_color *outp;
519       int data_left = datalen;
520       int pixels_left = width;
521       i_sample_t sample;
522       
523       if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
524         i_push_error(0, "SGI image: cannot seek to RLE data");
525         goto ErrorReturn;
526       }
527       if (i_io_read(ig, databuf, datalen) != datalen) {
528         i_push_error(0, "SGI image: cannot read RLE data");
529         goto ErrorReturn;
530       }
531       
532       inp = databuf;
533       outp = linebuf;
534       while (data_left) {
535         int code = *inp++;
536         int count = code & 0x7f;
537         --data_left;
538
539         if (count == 0)
540           break;
541         if (code & 0x80) {
542           /* literal run */
543           /* sanity checks */
544           if (count > pixels_left) {
545             i_push_error(0, "SGI image: literal run overflows scanline");
546             goto ErrorReturn;
547           }
548           if (count > data_left) {
549             i_push_error(0, "SGI image: literal run consumes more data than available");
550             goto ErrorReturn;
551           }
552           /* copy the run */
553           pixels_left -= count;
554           data_left -= count;
555           if (pixmin == 0 && pixmax == 255) {
556             while (count-- > 0) {
557               outp->channel[c] = *inp++;
558               ++outp;
559             }
560           }
561           else {
562             while (count-- > 0) {
563               int sample = *inp++;
564               if (sample < pixmin)
565                 sample = 0;
566               else if (sample > pixmax)
567                 sample = outmax;
568               else
569                 sample -= pixmin;
570               outp->channel[c] = sample * 255 / outmax;
571               ++outp;
572             }
573           }
574         }
575         else {
576           /* RLE run */
577           if (count > pixels_left) {
578             i_push_error(0, "SGI image: RLE run overflows scanline");
579             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]));
580             goto ErrorReturn;
581           }
582           if (data_left < 1) {
583             i_push_error(0, "SGI image: RLE run has no data for pixel");
584             goto ErrorReturn;
585           }
586           sample = *inp++;
587           if (pixmin != 0 || pixmax != 255) {
588             if (sample < pixmin)
589               sample = 0;
590             else if (sample > pixmax)
591               sample = outmax;
592             else
593               sample -= pixmin;
594             sample = sample * 255 / outmax;
595           }
596           --data_left;
597           pixels_left -= count;
598           while (count-- > 0) {
599             outp->channel[c] = sample;
600             ++outp;
601           }
602         }
603       }
604       /* must have a full scanline */
605       if (pixels_left) {
606         i_push_error(0, "SGI image: incomplete RLE scanline");
607         goto ErrorReturn;
608       }
609       /* must have used all of the data */
610       if (data_left) {
611         i_push_errorf(0, "SGI image: unused RLE data");
612         goto ErrorReturn;
613       }
614     }
615     i_plin(img, 0, width, height-1-y, linebuf);
616   }
617
618   myfree(linebuf);
619   myfree(databuf);
620   myfree(start_tab);
621   myfree(length_tab);
622
623   return img;
624
625  ErrorReturn:
626   if (linebuf)
627     myfree(linebuf);
628   if (databuf)
629     myfree(databuf);
630   myfree(start_tab);
631   myfree(length_tab);
632   i_img_destroy(img);
633   return NULL;
634 }
635
636 static i_img *
637 read_rgb_16_verbatim(i_img *img, io_glue *ig, rgb_header const *header) {
638   i_fcolor *linebuf;
639   unsigned char *databuf;
640   int c, y;
641   int savemask;
642   i_img_dim width = i_img_get_width(img);
643   i_img_dim height = i_img_get_height(img);
644   int channels = i_img_getchannels(img);
645   int pixmin = header->pixmin;
646   int pixmax = header->pixmax;
647   int outmax = pixmax - pixmin;
648   
649   linebuf   = mymalloc(width * sizeof(i_fcolor));  /* checked 31Jul07 TonyC */
650   databuf   = mymalloc(width * 2);  /* checked 31Jul07 TonyC */
651
652   savemask = i_img_getmask(img);
653
654   for(c = 0; c < channels; c++) {
655     i_img_setmask(img, 1<<c);
656     for(y = 0; y < height; y++) {
657       int x;
658       
659       if (i_io_read(ig, databuf, width*2) != width*2) {
660         i_push_error(0, "SGI image: cannot read image data");
661         i_img_destroy(img);
662         myfree(linebuf);
663         myfree(databuf);
664         return NULL;
665       }
666
667       if (pixmin == 0 && pixmax == 65535) {
668         for(x = 0; x < img->xsize; x++)
669           linebuf[x].channel[c] = (databuf[x*2] * 256 + databuf[x*2+1]) / 65535.0;
670       }
671       else {
672         for(x = 0; x < img->xsize; x++) {
673           int sample = databuf[x*2] * 256 + databuf[x*2+1];
674           if (sample < pixmin)
675             sample = 0;
676           else if (sample > pixmax)
677             sample = outmax;
678           else
679             sample -= pixmin;
680             
681           linebuf[x].channel[c] = (double)sample / outmax;
682         }
683       }
684       
685       i_plinf(img, 0, width, height-1-y, linebuf);
686     }
687   }
688   i_img_setmask(img, savemask);
689
690   myfree(linebuf);
691   myfree(databuf);
692   
693   return img;
694 }
695
696 static i_img *
697 read_rgb_16_rle(i_img *img, io_glue *ig, rgb_header const *header) {
698   i_fcolor *linebuf = NULL;
699   unsigned char *databuf = NULL;
700   unsigned long *start_tab, *length_tab;
701   unsigned long max_length;
702   i_img_dim width = i_img_get_width(img);
703   i_img_dim height = i_img_get_height(img);
704   int channels = i_img_getchannels(img);
705   i_img_dim y;
706   int c;
707   int pixmin = header->pixmin;
708   int pixmax = header->pixmax;
709   int outmax = pixmax - pixmin;
710
711   if (!read_rle_tables(ig, img,  
712                        &start_tab, &length_tab, &max_length)) {
713     i_img_destroy(img);
714     return NULL;
715   }
716
717   mm_log((1, "maxlen for an rle buffer: %lu\n", max_length));
718
719   if (max_length > (img->xsize * 2 + 1) * 2) {
720     i_push_errorf(0, "SGI image: ridiculous RLE line length %lu", max_length);
721     goto ErrorReturn;
722   }
723
724   linebuf = mymalloc(width*sizeof(i_fcolor)); /* checked 31Jul07 TonyC */
725   databuf = mymalloc(max_length); /* checked 31Jul07 TonyC */
726
727   for(y = 0; y < img->ysize; y++) {
728     for(c = 0; c < channels; c++) {
729       int ci = height * c + y;
730       int datalen = length_tab[ci];
731       unsigned char *inp;
732       i_fcolor *outp;
733       int data_left = datalen;
734       int pixels_left = width;
735       int sample;
736       
737       if (datalen & 1) {
738         i_push_error(0, "SGI image: invalid RLE length value for BPC=2");
739         goto ErrorReturn;
740       }
741       if (i_io_seek(ig, start_tab[ci], SEEK_SET) != start_tab[ci]) {
742         i_push_error(0, "SGI image: cannot seek to RLE data");
743         goto ErrorReturn;
744       }
745       if (i_io_read(ig, databuf, datalen) != datalen) {
746         i_push_error(0, "SGI image: cannot read RLE data");
747         goto ErrorReturn;
748       }
749       
750       inp = databuf;
751       outp = linebuf;
752       while (data_left > 0) {
753         int code = inp[0] * 256 + inp[1];
754         int count = code & 0x7f;
755         inp += 2;
756         data_left -= 2;
757
758         if (count == 0)
759           break;
760         if (code & 0x80) {
761           /* literal run */
762           /* sanity checks */
763           if (count > pixels_left) {
764             i_push_error(0, "SGI image: literal run overflows scanline");
765             goto ErrorReturn;
766           }
767           if (count > data_left) {
768             i_push_error(0, "SGI image: literal run consumes more data than available");
769             goto ErrorReturn;
770           }
771           /* copy the run */
772           pixels_left -= count;
773           data_left -= count * 2;
774           if (pixmin == 0 && pixmax == 65535) {
775             while (count-- > 0) {
776               outp->channel[c] = (inp[0] * 256 + inp[1]) / 65535.0;
777               inp += 2;
778               ++outp;
779             }
780           }
781           else {
782             while (count-- > 0) {
783               int sample = inp[0] * 256 + inp[1];
784               if (sample < pixmin)
785                 sample = 0;
786               else if (sample > pixmax)
787                 sample = outmax;
788               else
789                 sample -= pixmin;
790               outp->channel[c] = (double)sample / outmax;
791               ++outp;
792               inp += 2;
793             }
794           }
795         }
796         else {
797           double fsample;
798           /* RLE run */
799           if (count > pixels_left) {
800             i_push_error(0, "SGI image: RLE run overflows scanline");
801             goto ErrorReturn;
802           }
803           if (data_left < 2) {
804             i_push_error(0, "SGI image: RLE run has no data for pixel");
805             goto ErrorReturn;
806           }
807           sample = inp[0] * 256 + inp[1];
808           inp += 2;
809           data_left -= 2;
810           if (pixmin != 0 || pixmax != 65535) {
811             if (sample < pixmin)
812               sample = 0;
813             else if (sample > pixmax)
814               sample = outmax;
815             else
816               sample -= pixmin;
817             fsample = (double)sample / outmax;
818           }
819           else {
820             fsample = (double)sample / 65535.0;
821           }
822           pixels_left -= count;
823           while (count-- > 0) {
824             outp->channel[c] = fsample;
825             ++outp;
826           }
827         }
828       }
829       /* must have a full scanline */
830       if (pixels_left) {
831         i_push_error(0, "SGI image: incomplete RLE scanline");
832         goto ErrorReturn;
833       }
834       /* must have used all of the data */
835       if (data_left) {
836         i_push_errorf(0, "SGI image: unused RLE data");
837         goto ErrorReturn;
838       }
839     }
840     i_plinf(img, 0, width, height-1-y, linebuf);
841   }
842
843   myfree(linebuf);
844   myfree(databuf);
845   myfree(start_tab);
846   myfree(length_tab);
847
848   return img;
849
850  ErrorReturn:
851   if (linebuf)
852     myfree(linebuf);
853   if (databuf)
854     myfree(databuf);
855   myfree(start_tab);
856   myfree(length_tab);
857   i_img_destroy(img);
858   return NULL;
859 }
860
861 static int
862 write_sgi_header(i_img *img, io_glue *ig, int *rle, int *bpc2) {
863   rgb_header header;
864   unsigned char headbuf[512] = { 0 };
865
866   header.imagic = SGI_MAGIC;
867   if (!i_tags_get_int(&img->tags, "sgi_rle", 0, rle))
868     *rle = 0;
869   header.storagetype = *rle ? SGI_STORAGE_RLE : SGI_STORAGE_VERBATIM;
870   header.pixmin = 0;
871   header.colormap = SGI_COLORMAP_NORMAL;
872   *bpc2 = img->bits > 8;
873   if (*bpc2) {
874     header.BPC = 2;
875     header.pixmax = 65535;
876   }
877   else {
878     header.BPC = 1;
879     header.pixmax = 255;
880   }
881   if (img->channels == 1) {
882     header.dimensions = 2;
883   }
884   else {
885     header.dimensions = 3;
886   }
887   header.xsize = img->xsize;
888   header.ysize = img->ysize;
889   header.zsize = img->channels;
890   memset(header.name, 0, sizeof(header.name));
891   i_tags_get_string(&img->tags, "i_comment",  0, 
892                     header.name, sizeof(header.name));
893
894   rgb_header_pack(&header, headbuf);
895
896   if (i_io_write(ig, headbuf, sizeof(headbuf)) != sizeof(headbuf)) {
897     i_push_error(0, "SGI image: cannot write header");
898     return 0;
899   }
900
901   return 1;
902 }
903
904 static int
905 write_sgi_8_verb(i_img *img, io_glue *ig) {
906   i_sample_t *linebuf;
907   i_img_dim width = img->xsize;
908   int c;
909   i_img_dim y;
910
911   linebuf = mymalloc(width);  /* checked 31Jul07 TonyC */
912   for (c = 0; c < img->channels; ++c) {
913     for (y = img->ysize - 1; y >= 0; --y) {
914       i_gsamp(img, 0, width, y, linebuf, &c, 1);
915       if (i_io_write(ig, linebuf, width) != width) {
916         i_push_error(errno, "SGI image: error writing image data");
917         myfree(linebuf);
918         return 0;
919       }
920     }
921   }
922   myfree(linebuf);
923
924   if (i_io_close(ig))
925     return 0;
926
927   return 1;
928 }
929
930 static int
931 write_sgi_8_rle(i_img *img, io_glue *ig) {
932   i_sample_t *linebuf;
933   unsigned char *comp_buf;
934   i_img_dim width = img->xsize;
935   int c;
936   i_img_dim y;
937   unsigned char *offsets;
938   unsigned char *lengths;
939   int offset_pos = 0;
940   size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2;
941   unsigned long start_offset = 512 + offsets_size;
942   unsigned long current_offset = start_offset;
943   int in_left;
944   unsigned char *outp;
945   i_sample_t *inp;
946   size_t comp_size;
947
948   if (offsets_size / 2 / 4 / img->channels != img->ysize) {
949     i_push_error(0, "SGI image: integer overflow calculating allocation size");
950     return 0;
951   }
952
953   linebuf = mymalloc(width);  /* checked 31Jul07 TonyC */
954   comp_buf = mymalloc((width + 1) * 2);  /* checked 31Jul07 TonyC */
955   offsets = mymalloc(offsets_size);
956   memset(offsets, 0, offsets_size);
957   if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
958     i_push_error(errno, "SGI image: error writing offsets/lengths");
959     goto Error;
960   }
961   lengths = offsets + img->ysize * img->channels * 4;
962   for (c = 0; c < img->channels; ++c) {
963     for (y = img->ysize - 1; y >= 0; --y) {
964       i_gsamp(img, 0, width, y, linebuf, &c, 1);
965       in_left = width;
966       outp = comp_buf;
967       inp = linebuf;
968       while (in_left) {
969         unsigned char *run_start = inp;
970
971         /* first try for an RLE run */
972         int run_length = 1;
973         while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) {
974           ++run_length;
975           ++inp;
976         }
977         if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) {
978           ++run_length;
979           ++inp;
980         }
981         if (run_length > 2) {
982           *outp++ = run_length;
983           *outp++ = inp[0];
984           inp++;
985           in_left -= run_length;
986         }
987         else {
988           inp = run_start;
989
990           /* scan for a literal run */
991           run_length = 1;
992           run_start = inp;
993           while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) {
994             ++run_length;
995             ++inp;
996           }
997           ++inp;
998           
999           /* fill out the run if 2 or less samples left and there's space */
1000           if (in_left - run_length <= 2 
1001               && in_left <= 127) {
1002             run_length = in_left;
1003           }
1004           in_left -= run_length;
1005           *outp++ = run_length | 0x80;
1006           while (run_length--) {
1007             *outp++ = *run_start++;
1008           }
1009         }
1010       }
1011       *outp++ = 0;
1012       comp_size = outp - comp_buf;
1013       store_32(offsets + offset_pos, current_offset);
1014       store_32(lengths + offset_pos, comp_size);
1015       offset_pos += 4;
1016       current_offset += comp_size;
1017       if (i_io_write(ig, comp_buf, comp_size) != comp_size) {
1018         i_push_error(errno, "SGI image: error writing RLE data");
1019         goto Error;
1020       }
1021     }
1022   }
1023
1024   /* seek back to store the offsets and lengths */
1025   if (i_io_seek(ig, 512, SEEK_SET) != 512) {
1026     i_push_error(errno, "SGI image: cannot seek to RLE table");
1027     goto Error;
1028   }
1029
1030   if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
1031     i_push_error(errno, "SGI image: cannot write final RLE table");
1032     goto Error;
1033   }
1034
1035   myfree(offsets);
1036   myfree(comp_buf);
1037   myfree(linebuf);
1038
1039   if (i_io_close(ig))
1040     return 0;
1041
1042   return 1;
1043
1044  Error:
1045   myfree(offsets);
1046   myfree(comp_buf);
1047   myfree(linebuf);
1048   return 0;
1049 }
1050
1051 static int
1052 write_sgi_16_verb(i_img *img, io_glue *ig) {
1053   i_fsample_t *linebuf;
1054   unsigned char *encbuf;
1055   unsigned char *outp;
1056   i_img_dim width = img->xsize;
1057   int c;
1058   i_img_dim x;
1059   i_img_dim y;
1060
1061   linebuf = mymalloc(width * sizeof(i_fsample_t));  /* checked 31Jul07 TonyC */
1062   encbuf = mymalloc(width * 2);  /* checked 31Jul07 TonyC */
1063   for (c = 0; c < img->channels; ++c) {
1064     for (y = img->ysize - 1; y >= 0; --y) {
1065       i_gsampf(img, 0, width, y, linebuf, &c, 1);
1066       for (x = 0, outp = encbuf; x < width; ++x, outp+=2) {
1067         unsigned short samp16 = SampleFTo16(linebuf[x]);
1068         store_16(outp, samp16);
1069       }
1070       if (i_io_write(ig, encbuf, width * 2) != width * 2) {
1071         i_push_error(errno, "SGI image: error writing image data");
1072         myfree(linebuf);
1073         myfree(encbuf);
1074         return 0;
1075       }
1076     }
1077   }
1078   myfree(linebuf);
1079   myfree(encbuf);
1080
1081   if (i_io_close(ig))
1082     return 0;
1083
1084   return 1;
1085 }
1086
1087 static int
1088 write_sgi_16_rle(i_img *img, io_glue *ig) {
1089   i_fsample_t *sampbuf;
1090   unsigned short *linebuf;
1091   unsigned char *comp_buf;
1092   i_img_dim width = img->xsize;
1093   int c;
1094   i_img_dim y;
1095   unsigned char *offsets;
1096   unsigned char *lengths;
1097   int offset_pos = 0;
1098   size_t offsets_size = (size_t)4 * img->ysize * img->channels * 2;
1099   unsigned long start_offset = 512 + offsets_size;
1100   unsigned long current_offset = start_offset;
1101   int in_left;
1102   unsigned char *outp;
1103   unsigned short *inp;
1104   size_t comp_size;
1105   i_img_dim x;
1106
1107   if (offsets_size / 4 / 2 / img->channels != img->ysize) {
1108     i_push_error(0, "SGI image: integer overflow calculating allocation size");
1109     return 0;
1110   }
1111
1112   sampbuf = mymalloc(width * sizeof(i_fsample_t));  /* checked 31Jul07 TonyC */
1113   linebuf = mymalloc(width * sizeof(unsigned short));  /* checked 31Jul07 TonyC */
1114   comp_buf = mymalloc((width + 1) * 2 * 2);  /* checked 31Jul07 TonyC */
1115   offsets = mymalloc(offsets_size);
1116   memset(offsets, 0, offsets_size);
1117   if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
1118     i_push_error(errno, "SGI image: error writing offsets/lengths");
1119     goto Error;
1120   }
1121   lengths = offsets + img->ysize * img->channels * 4;
1122   for (c = 0; c < img->channels; ++c) {
1123     for (y = img->ysize - 1; y >= 0; --y) {
1124       i_gsampf(img, 0, width, y, sampbuf, &c, 1);
1125       for (x = 0; x < width; ++x)
1126         linebuf[x] = (unsigned short)(SampleFTo16(sampbuf[x]));
1127       in_left = width;
1128       outp = comp_buf;
1129       inp = linebuf;
1130       while (in_left) {
1131         unsigned short *run_start = inp;
1132
1133         /* first try for an RLE run */
1134         int run_length = 1;
1135         while (in_left - run_length >= 2 && inp[0] == inp[1] && run_length < 127) {
1136           ++run_length;
1137           ++inp;
1138         }
1139         if (in_left - run_length == 1 && inp[0] == inp[1] && run_length < 127) {
1140           ++run_length;
1141           ++inp;
1142         }
1143         if (run_length > 2) {
1144           store_16(outp, run_length);
1145           store_16(outp+2, inp[0]);
1146           outp += 4;
1147           inp++;
1148           in_left -= run_length;
1149         }
1150         else {
1151           inp = run_start;
1152
1153           /* scan for a literal run */
1154           run_length = 1;
1155           run_start = inp;
1156           while (in_left - run_length > 1 && (inp[0] != inp[1] || inp[1] != inp[2]) && run_length < 127) {
1157             ++run_length;
1158             ++inp;
1159           }
1160           ++inp;
1161           
1162           /* fill out the run if 2 or less samples left and there's space */
1163           if (in_left - run_length <= 2 
1164               && in_left <= 127) {
1165             run_length = in_left;
1166           }
1167           in_left -= run_length;
1168           store_16(outp, run_length | 0x80);
1169           outp += 2;
1170           while (run_length--) {
1171             store_16(outp, *run_start++);
1172             outp += 2;
1173           }
1174         }
1175       }
1176       store_16(outp, 0);
1177       outp += 2;
1178       comp_size = outp - comp_buf;
1179       store_32(offsets + offset_pos, current_offset);
1180       store_32(lengths + offset_pos, comp_size);
1181       offset_pos += 4;
1182       current_offset += comp_size;
1183       if (i_io_write(ig, comp_buf, comp_size) != comp_size) {
1184         i_push_error(errno, "SGI image: error writing RLE data");
1185         goto Error;
1186       }
1187     }
1188   }
1189
1190   /* seek back to store the offsets and lengths */
1191   if (i_io_seek(ig, 512, SEEK_SET) != 512) {
1192     i_push_error(errno, "SGI image: cannot seek to RLE table");
1193     goto Error;
1194   }
1195
1196   if (i_io_write(ig, offsets, offsets_size) != offsets_size) {
1197     i_push_error(errno, "SGI image: cannot write final RLE table");
1198     goto Error;
1199   }
1200
1201   myfree(offsets);
1202   myfree(comp_buf);
1203   myfree(linebuf);
1204   myfree(sampbuf);
1205
1206   if (i_io_close(ig))
1207     return 0;
1208
1209   return 1;
1210
1211  Error:
1212   myfree(offsets);
1213   myfree(comp_buf);
1214   myfree(linebuf);
1215   myfree(sampbuf);
1216
1217   return 0;
1218 }