1 /*
2  * SGI image file format library routines.
3  *
4  * Copyright 1997-1998 Michael Sweet (mike@easysw.com)
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  *
19  * Contents:
20  *
21  *   sgiClose()    - Close an SGI image file.
22  *   sgiGetRow()   - Get a row of image data from a file.
23  *   sgiOpen()     - Open an SGI image file for reading or writing.
24  *   sgiOpenFile() - Open an SGI image file for reading or writing.
25  *   sgiPutRow()   - Put a row of image data to a file.
26  *   getlong()     - Get a 32-bit big-endian integer.
27  *   getshort()    - Get a 16-bit big-endian integer.
28  *   putlong()     - Put a 32-bit big-endian integer.
29  *   putshort()    - Put a 16-bit big-endian integer.
30  *   read_rle8()   - Read 8-bit RLE data.
31  *   read_rle16()  - Read 16-bit RLE data.
32  *   write_rle8()  - Write 8-bit RLE data.
33  *   write_rle16() - Write 16-bit RLE data.
34  *
35  * Revision History:
36  *
37  *   $Log$
38  *   Revision 1.9  2005/03/04 13:23:31  neo
39  *   2005-03-04  Sven Neumann  <sven@gimp.org>
40  *
41  *      * plug-ins/FractalExplorer
42  *      * plug-ins/Lighting
43  *      * plug-ins/bmp
44  *      * plug-ins/dbbrowser
45  *      * plug-ins/faxg3
46  *      * plug-ins/fits
47  *      * plug-ins/flame
48  *      * plug-ins/gfig
49  *      * plug-ins/gflare
50  *      * plug-ins/gfli
51  *      * plug-ins/gimpressionist
52  *      * plug-ins/ifscompose
53  *      * plug-ins/jpeg
54  *      * plug-ins/maze
55  *      * plug-ins/pagecurl
56  *      * plug-ins/print
57  *      * plug-ins/rcm
58  *      * plug-ins/script-fu
59  *      * plug-ins/sel2path
60  *      * plug-ins/sgi
61  *      * plug-ins/twain
62  *      * plug-ins/winicon
63  *      * plug-ins/xjt: ported to gstdio, removed unnecessary includes,
64  *      minor fixes to filename handling here and there.
65  *
66  *   Revision 1.8  2003/04/07 11:59:33  neo
67  *   2003-04-07  Sven Neumann  <sven@gimp.org>
68  *
69  *      * plug-ins/sgi/sgi.h
70  *      * plug-ins/sgi/sgilib.c: applied a patch from marek@aki.cz that
71  *      adds support for reading SGI files in little-endian format. Fixes
72  *      bug #106610.
73  *
74  *   Revision 1.7  1998/06/06 23:22:21  yosh
75  *   * adding Lighting plugin
76  *
77  *   * updated despeckle, png, sgi, and sharpen
78  *
79  *   -Yosh
80  *
81  *   Revision 1.5  1998/04/23  17:40:49  mike
82  *   Updated to support 16-bit <unsigned> image data.
83  *
84  *   Revision 1.4  1998/02/05  17:10:58  mike
85  *   Added sgiOpenFile() function for opening an existing file pointer.
86  *
87  *   Revision 1.3  1997/07/02  16:40:16  mike
88  *   sgiOpen() wasn't opening files with "rb" or "wb+".  This caused problems
89  *   on PCs running Windows/DOS...
90  *
91  *   Revision 1.2  1997/06/18  00:55:28  mike
92  *   Updated to hold length table when writing.
93  *   Updated to hold current length when doing ARLE.
94  *   Wasn't writing length table on close.
95  *   Wasn't saving new line into arle_row when necessary.
96  *
97  *   Revision 1.1  1997/06/15  03:37:19  mike
98  *   Initial revision
99  */
100 
101 #include "config.h"
102 
103 #include <stdlib.h>
104 #include <string.h>
105 
106 #include <glib.h>
107 #include <glib/gstdio.h>
108 
109 #include "sgi-lib.h"
110 
111 
112 /*
113  * Local functions...
114  */
115 
116 static int      getlong(sgi_t*);
117 static int      getshort(sgi_t*);
118 static int      putlong(long, sgi_t*);
119 static int      putshort(unsigned short, sgi_t*);
120 static int      read_rle8(sgi_t*, unsigned short *, int);
121 static int      read_rle16(sgi_t*, unsigned short *, int);
122 static int      write_rle8(sgi_t*, unsigned short *, int);
123 static int      write_rle16(sgi_t*, unsigned short *, int);
124 
125 
126 /*
127  * 'sgiClose()' - Close an SGI image file.
128  */
129 
130 int
sgiClose(sgi_t * sgip)131 sgiClose(sgi_t *sgip)   /* I - SGI image */
132 {
133   int   i;              /* Return status */
134   long  *offset;        /* Looping var for offset table */
135 
136 
137   if (sgip == NULL)
138     return (-1);
139 
140   if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE)
141   {
142    /*
143     * Write the scanline offset table to the file...
144     */
145 
146     fseek(sgip->file, 512, SEEK_SET);
147 
148     for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0];
149          i > 0;
150          i --, offset ++)
151       if (putlong(offset[0], sgip) < 0)
152         return (-1);
153 
154     for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0];
155          i > 0;
156          i --, offset ++)
157       if (putlong(offset[0], sgip) < 0)
158         return (-1);
159   };
160 
161   if (sgip->table != NULL)
162   {
163     free(sgip->table[0]);
164     free(sgip->table);
165   };
166 
167   if (sgip->length != NULL)
168   {
169     free(sgip->length[0]);
170     free(sgip->length);
171   };
172 
173   if (sgip->comp == SGI_COMP_ARLE)
174     free(sgip->arle_row);
175 
176   i = fclose(sgip->file);
177   free(sgip);
178 
179   return (i);
180 }
181 
182 
183 /*
184  * 'sgiGetRow()' - Get a row of image data from a file.
185  */
186 
187 int
sgiGetRow(sgi_t * sgip,unsigned short * row,int y,int z)188 sgiGetRow(sgi_t          *sgip, /* I - SGI image */
189           unsigned short *row,  /* O - Row to read */
190           int            y,     /* I - Line to read */
191           int            z)     /* I - Channel to read */
192 {
193   int   x;              /* X coordinate */
194   long  offset;         /* File offset */
195 
196 
197   if (sgip == NULL ||
198       row == NULL ||
199       y < 0 || y >= sgip->ysize ||
200       z < 0 || z >= sgip->zsize)
201     return (-1);
202 
203   switch (sgip->comp)
204   {
205     case SGI_COMP_NONE :
206        /*
207         * Seek to the image row - optimize buffering by only seeking if
208         * necessary...
209         */
210 
211         offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
212         if (offset != ftell(sgip->file))
213           fseek(sgip->file, offset, SEEK_SET);
214 
215         if (sgip->bpp == 1)
216         {
217           for (x = sgip->xsize; x > 0; x --, row ++)
218             *row = getc(sgip->file);
219         }
220         else
221         {
222           for (x = sgip->xsize; x > 0; x --, row ++)
223             *row = getshort(sgip);
224         };
225         break;
226 
227     case SGI_COMP_RLE :
228         offset = sgip->table[z][y];
229         if (offset != ftell(sgip->file))
230           fseek(sgip->file, offset, SEEK_SET);
231 
232         if (sgip->bpp == 1)
233           return (read_rle8(sgip, row, sgip->xsize));
234         else
235           return (read_rle16(sgip, row, sgip->xsize));
236         break;
237   };
238 
239   return (0);
240 }
241 
242 
243 /*
244  * 'sgiOpen()' - Open an SGI image file for reading or writing.
245  */
246 
247 sgi_t *
sgiOpen(const char * filename,int mode,int comp,int bpp,int xsize,int ysize,int zsize)248 sgiOpen(const char *filename,   /* I - File to open */
249         int         mode,       /* I - Open mode (SGI_READ or SGI_WRITE) */
250         int         comp,       /* I - Type of compression */
251         int         bpp,        /* I - Bytes per pixel */
252         int         xsize,      /* I - Width of image in pixels */
253         int         ysize,      /* I - Height of image in pixels */
254         int         zsize)      /* I - Number of channels */
255 {
256   sgi_t *sgip;          /* New SGI image file */
257   FILE  *file;          /* Image file pointer */
258 
259 
260   if (mode == SGI_READ)
261     file = g_fopen(filename, "rb");
262   else
263     file = g_fopen(filename, "w+b");
264 
265   if (file == NULL)
266     return (NULL);
267 
268   if ((sgip = sgiOpenFile(file, mode, comp, bpp, xsize, ysize, zsize)) == NULL)
269     fclose(file);
270 
271   return (sgip);
272 }
273 
274 
275 /*
276  * 'sgiOpenFile()' - Open an SGI image file for reading or writing.
277  */
278 
279 sgi_t *
sgiOpenFile(FILE * file,int mode,int comp,int bpp,int xsize,int ysize,int zsize)280 sgiOpenFile(FILE *file, /* I - File to open */
281             int  mode,  /* I - Open mode (SGI_READ or SGI_WRITE) */
282             int  comp,  /* I - Type of compression */
283             int  bpp,   /* I - Bytes per pixel */
284             int  xsize, /* I - Width of image in pixels */
285             int  ysize, /* I - Height of image in pixels */
286             int  zsize) /* I - Number of channels */
287 {
288   int   i, j;           /* Looping var */
289   char  name[80];       /* Name of file in image header */
290   short magic;          /* Magic number */
291   sgi_t *sgip;          /* New image pointer */
292 
293 
294   if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL)
295     return (NULL);
296 
297   sgip->file = file;
298   sgip->swapBytes = 0;
299 
300   switch (mode)
301   {
302     case SGI_READ :
303         sgip->mode = SGI_READ;
304 
305         magic = getshort(sgip);
306         if (magic != SGI_MAGIC)
307         {
308           /* try little endian format */
309           magic = ((magic >> 8) & 0x00ff) | ((magic << 8) & 0xff00);
310           if(magic != SGI_MAGIC) {
311             free(sgip);
312             return (NULL);
313           } else {
314             sgip->swapBytes = 1;
315           }
316         }
317 
318         sgip->comp  = getc(sgip->file);
319         sgip->bpp   = getc(sgip->file);
320         getshort(sgip);         /* Dimensions */
321         sgip->xsize = getshort(sgip);
322         sgip->ysize = getshort(sgip);
323         sgip->zsize = getshort(sgip);
324         getlong(sgip);          /* Minimum pixel */
325         getlong(sgip);          /* Maximum pixel */
326 
327         if (sgip->comp)
328         {
329          /*
330           * This file is compressed; read the scanline tables...
331           */
332 
333           fseek(sgip->file, 512, SEEK_SET);
334 
335           sgip->table    = calloc(sgip->zsize, sizeof(long *));
336           if (sgip->table == NULL)
337             {
338               free(sgip);
339               return (NULL);
340             }
341           sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
342           if (sgip->table[0] == NULL)
343             {
344               free(sgip->table);
345               free(sgip);
346               return (NULL);
347             }
348           for (i = 1; i < sgip->zsize; i ++)
349             sgip->table[i] = sgip->table[0] + i * sgip->ysize;
350 
351           for (i = 0; i < sgip->zsize; i ++)
352             for (j = 0; j < sgip->ysize; j ++)
353               sgip->table[i][j] = getlong(sgip);
354         };
355         break;
356 
357     case SGI_WRITE :
358         if (xsize < 1 ||
359             ysize < 1 ||
360             zsize < 1 ||
361             bpp < 1 || bpp > 2 ||
362             comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE)
363         {
364           free(sgip);
365           return (NULL);
366         };
367 
368         sgip->mode = SGI_WRITE;
369 
370         putshort(SGI_MAGIC, sgip);
371         putc((sgip->comp = comp) != 0, sgip->file);
372         putc(sgip->bpp = bpp, sgip->file);
373         putshort(3, sgip);              /* Dimensions */
374         putshort(sgip->xsize = xsize, sgip);
375         putshort(sgip->ysize = ysize, sgip);
376         putshort(sgip->zsize = zsize, sgip);
377         if (bpp == 1)
378         {
379           putlong(0, sgip);     /* Minimum pixel */
380           putlong(255, sgip);   /* Maximum pixel */
381         }
382         else
383         {
384           putlong(-32768, sgip);        /* Minimum pixel */
385           putlong(32767, sgip); /* Maximum pixel */
386         };
387         putlong(0, sgip);               /* Reserved */
388 
389         memset(name, 0, sizeof(name));
390         fwrite(name, sizeof(name), 1, sgip->file);
391 
392         for (i = 0; i < 102; i ++)
393           putlong(0, sgip);
394 
395         switch (comp)
396         {
397           case SGI_COMP_NONE : /* No compression */
398              /*
399               * This file is uncompressed.  To avoid problems with sparse files,
400               * we need to write blank pixels for the entire image...
401               */
402 
403               if (bpp == 1)
404               {
405                 for (i = xsize * ysize * zsize; i > 0; i --)
406                   putc(0, sgip->file);
407               }
408               else
409               {
410                 for (i = xsize * ysize * zsize; i > 0; i --)
411                   putshort(0, sgip);
412               };
413               break;
414 
415           case SGI_COMP_ARLE : /* Aggressive RLE */
416               sgip->arle_row    = (unsigned short *)calloc(xsize, sizeof(unsigned short));
417               if (sgip->arle_row == NULL)
418                 {
419                   free(sgip);
420                   return (NULL);
421                 }
422               sgip->arle_offset = 0;
423 
424           case SGI_COMP_RLE : /* Run-Length Encoding */
425              /*
426               * This file is compressed; write the (blank) scanline tables...
427               */
428 
429               for (i = 2 * ysize * zsize; i > 0; i --)
430                 putlong(0, sgip);
431 
432               sgip->firstrow = ftell(sgip->file);
433               sgip->nextrow  = ftell(sgip->file);
434               sgip->table    = calloc(sgip->zsize, sizeof(long *));
435               if (sgip->table == NULL)
436                 {
437                   free(sgip->arle_row);
438                   free(sgip);
439                   return (NULL);
440                 }
441               sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
442               if (sgip->table[0] == NULL)
443                 {
444                   free(sgip->table);
445                   free(sgip->arle_row);
446                   free(sgip);
447                   return (NULL);
448                 }
449               for (i = 1; i < sgip->zsize; i ++)
450                 sgip->table[i] = sgip->table[0] + i * sgip->ysize;
451               sgip->length    = calloc(sgip->zsize, sizeof(long *));
452               sgip->length[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long));
453               for (i = 1; i < sgip->zsize; i ++)
454                 sgip->length[i] = sgip->length[0] + i * sgip->ysize;
455               break;
456         };
457         break;
458 
459     default :
460         free(sgip);
461         return (NULL);
462   };
463 
464   return (sgip);
465 }
466 
467 
468 /*
469  * 'sgiPutRow()' - Put a row of image data to a file.
470  */
471 
472 int
sgiPutRow(sgi_t * sgip,unsigned short * row,int y,int z)473 sgiPutRow(sgi_t          *sgip, /* I - SGI image */
474           unsigned short *row,  /* I - Row to write */
475           int            y,     /* I - Line to write */
476           int            z)     /* I - Channel to write */
477 {
478   int   x;              /* X coordinate */
479   long  offset;         /* File offset */
480 
481 
482   if (sgip == NULL ||
483       row == NULL ||
484       y < 0 || y >= sgip->ysize ||
485       z < 0 || z >= sgip->zsize)
486     return (-1);
487 
488   switch (sgip->comp)
489   {
490     case SGI_COMP_NONE :
491        /*
492         * Seek to the image row - optimize buffering by only seeking if
493         * necessary...
494         */
495 
496         offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp;
497         if (offset != ftell(sgip->file))
498           fseek(sgip->file, offset, SEEK_SET);
499 
500         if (sgip->bpp == 1)
501         {
502           for (x = sgip->xsize; x > 0; x --, row ++)
503             putc(*row, sgip->file);
504         }
505         else
506         {
507           for (x = sgip->xsize; x > 0; x --, row ++)
508             putshort(*row, sgip);
509         };
510         break;
511 
512     case SGI_COMP_ARLE :
513         if (sgip->table[z][y] != 0)
514           return (-1);
515 
516        /*
517         * First check the last row written...
518         */
519 
520         if (sgip->arle_offset > 0)
521         {
522           for (x = 0; x < sgip->xsize; x ++)
523             if (row[x] != sgip->arle_row[x])
524               break;
525 
526           if (x == sgip->xsize)
527           {
528             sgip->table[z][y]  = sgip->arle_offset;
529             sgip->length[z][y] = sgip->arle_length;
530             return (0);
531           };
532         };
533 
534        /*
535         * If that didn't match, search all the previous rows...
536         */
537 
538         fseek(sgip->file, sgip->firstrow, SEEK_SET);
539 
540         if (sgip->bpp == 1)
541         {
542           do
543           {
544             sgip->arle_offset = ftell(sgip->file);
545             if ((sgip->arle_length = read_rle8(sgip, sgip->arle_row, sgip->xsize)) < 0)
546             {
547               x = 0;
548               break;
549             };
550 
551             for (x = 0; x < sgip->xsize; x ++)
552               if (row[x] != sgip->arle_row[x])
553                 break;
554           }
555           while (x < sgip->xsize);
556         }
557         else
558         {
559           do
560           {
561             sgip->arle_offset = ftell(sgip->file);
562             if ((sgip->arle_length = read_rle16(sgip, sgip->arle_row, sgip->xsize)) < 0)
563             {
564               x = 0;
565               break;
566             };
567 
568             for (x = 0; x < sgip->xsize; x ++)
569               if (row[x] != sgip->arle_row[x])
570                 break;
571           }
572           while (x < sgip->xsize);
573         };
574 
575         if (x == sgip->xsize)
576         {
577           sgip->table[z][y]  = sgip->arle_offset;
578           sgip->length[z][y] = sgip->arle_length;
579           return (0);
580         }
581         else
582           fseek(sgip->file, 0, SEEK_END);       /* Clear EOF */
583 
584     case SGI_COMP_RLE :
585         if (sgip->table[z][y] != 0)
586           return (-1);
587 
588         offset = sgip->table[z][y] = sgip->nextrow;
589 
590         if (offset != ftell(sgip->file))
591           fseek(sgip->file, offset, SEEK_SET);
592 
593         if (sgip->bpp == 1)
594           x = write_rle8(sgip, row, sgip->xsize);
595         else
596           x = write_rle16(sgip, row, sgip->xsize);
597 
598         if (sgip->comp == SGI_COMP_ARLE)
599         {
600           sgip->arle_offset = offset;
601           sgip->arle_length = x;
602           memcpy(sgip->arle_row, row, sgip->xsize * sizeof(short));
603         };
604 
605         sgip->nextrow      = ftell(sgip->file);
606         sgip->length[z][y] = x;
607 
608         return (x);
609   };
610 
611   return (0);
612 }
613 
614 
615 /*
616  * 'getlong()' - Get a 32-bit big-endian integer.
617  */
618 
619 static int
getlong(sgi_t * sgip)620 getlong(sgi_t *sgip)    /* I - SGI image to read from */
621 {
622   unsigned char b[4];
623 
624 
625   fread(b, 4, 1, sgip->file);
626   if(sgip->swapBytes)
627     return ((b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]);
628   else
629     return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
630 }
631 
632 
633 /*
634  * 'getshort()' - Get a 16-bit big-endian integer.
635  */
636 
637 static int
getshort(sgi_t * sgip)638 getshort(sgi_t *sgip)   /* I - SGI image to read from */
639 {
640   unsigned char b[2];
641 
642 
643   fread(b, 2, 1, sgip->file);
644   if(sgip->swapBytes)
645     return ((b[1] << 8) | b[0]);
646   else
647     return ((b[0] << 8) | b[1]);
648 }
649 
650 
651 /*
652  * 'putlong()' - Put a 32-bit big-endian integer.
653  */
654 
655 static int
putlong(long n,sgi_t * sgip)656 putlong(long n,         /* I - Long to write */
657         sgi_t *sgip)    /* I - File to write to */
658 {
659   if (putc(n >> 24, sgip->file) == EOF)
660     return (EOF);
661   if (putc(n >> 16, sgip->file) == EOF)
662     return (EOF);
663   if (putc(n >> 8, sgip->file) == EOF)
664     return (EOF);
665   if (putc(n, sgip->file) == EOF)
666     return (EOF);
667   else
668     return (0);
669 }
670 
671 
672 /*
673  * 'putshort()' - Put a 16-bit big-endian integer.
674  */
675 
676 static int
putshort(unsigned short n,sgi_t * sgip)677 putshort(unsigned short n,      /* I - Short to write */
678          sgi_t *sgip)           /* I - File to write to */
679 {
680   if (putc(n >> 8, sgip->file) == EOF)
681     return (EOF);
682   if (putc(n, sgip->file) == EOF)
683     return (EOF);
684   else
685     return (0);
686 }
687 
688 
689 /*
690  * 'read_rle8()' - Read 8-bit RLE data.
691  */
692 
693 static int
read_rle8(sgi_t * sgip,unsigned short * row,int xsize)694 read_rle8(sgi_t *sgip,          /* I - SGI image to read from */
695           unsigned short *row,  /* O - Data */
696           int            xsize) /* I - Width of data in pixels */
697 {
698   int   i,              /* Looping var */
699         ch,             /* Current character */
700         count,          /* RLE count */
701         length;         /* Number of bytes read... */
702 
703 
704   length = 0;
705 
706   while (xsize > 0)
707   {
708     if ((ch = getc(sgip->file)) == EOF)
709       return (-1);
710     length ++;
711 
712     count = MIN (ch & 127, xsize);
713     if (count == 0)
714       break;
715 
716     if (ch & 128)
717     {
718       for (i = 0; i < count; i ++, row ++, xsize --, length ++)
719         *row = getc(sgip->file);
720     }
721     else
722     {
723       ch = getc(sgip->file);
724       length ++;
725       for (i = 0; i < count; i ++, row ++, xsize --)
726         *row = ch;
727     };
728   };
729 
730   return (xsize > 0 ? -1 : length);
731 }
732 
733 
734 /*
735  * 'read_rle16()' - Read 16-bit RLE data.
736  */
737 
738 static int
read_rle16(sgi_t * sgip,unsigned short * row,int xsize)739 read_rle16(sgi_t *sgip,         /* I - SGI image to read from */
740            unsigned short *row, /* O - Data */
741            int            xsize)/* I - Width of data in pixels */
742 {
743   int   i,              /* Looping var */
744         ch,             /* Current character */
745         count,          /* RLE count */
746         length;         /* Number of bytes read... */
747 
748 
749   length = 0;
750 
751   while (xsize > 0)
752   {
753     if ((ch = getshort(sgip)) == EOF)
754       return (-1);
755     length ++;
756 
757     count = MIN (ch & 127, xsize);
758     if (count == 0)
759       break;
760 
761     if (ch & 128)
762     {
763       for (i = 0; i < count; i ++, row ++, xsize --, length ++)
764         *row = getshort(sgip);
765     }
766     else
767     {
768       ch = getshort(sgip);
769       length ++;
770       for (i = 0; i < count; i ++, row ++, xsize --)
771         *row = ch;
772     };
773   };
774 
775   return (xsize > 0 ? -1 : length * 2);
776 }
777 
778 
779 /*
780  * 'write_rle8()' - Write 8-bit RLE data.
781  */
782 
783 static int
write_rle8(sgi_t * sgip,unsigned short * row,int xsize)784 write_rle8(sgi_t *sgip,         /* I - SGI image to write to */
785            unsigned short *row, /* I - Data */
786            int            xsize)/* I - Width of data in pixels */
787 {
788   int                   length, /* Length of output line */
789                         count,  /* Number of repeated/non-repeated pixels */
790                         i,      /* Looping var */
791                         x;      /* Looping var */
792   unsigned short        *start, /* Start of sequence */
793                         repeat; /* Repeated pixel */
794 
795 
796   for (x = xsize, length = 0; x > 0;)
797   {
798     start = row;
799     row   += 2;
800     x     -= 2;
801 
802     while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
803     {
804       row ++;
805       x --;
806     };
807 
808     row -= 2;
809     x   += 2;
810 
811     count = row - start;
812     while (count > 0)
813     {
814       i     = count > 126 ? 126 : count;
815       count -= i;
816 
817       if (putc(128 | i, sgip->file) == EOF)
818         return (-1);
819       length ++;
820 
821       while (i > 0)
822       {
823         if (putc(*start, sgip->file) == EOF)
824           return (-1);
825         start ++;
826         i --;
827         length ++;
828       };
829     };
830 
831     if (x <= 0)
832       break;
833 
834     start  = row;
835     repeat = row[0];
836 
837     row ++;
838     x --;
839 
840     while (x > 0 && *row == repeat)
841     {
842       row ++;
843       x --;
844     };
845 
846     count = row - start;
847     while (count > 0)
848     {
849       i     = count > 126 ? 126 : count;
850       count -= i;
851 
852       if (putc(i, sgip->file) == EOF)
853         return (-1);
854       length ++;
855 
856       if (putc(repeat, sgip->file) == EOF)
857         return (-1);
858       length ++;
859     };
860   };
861 
862   length ++;
863 
864   if (putc(0, sgip->file) == EOF)
865     return (-1);
866   else
867     return (length);
868 }
869 
870 
871 /*
872  * 'write_rle16()' - Write 16-bit RLE data.
873  */
874 
875 static int
write_rle16(sgi_t * sgip,unsigned short * row,int xsize)876 write_rle16(sgi_t *sgip,        /* I - SGI image to write to */
877             unsigned short *row,/* I - Data */
878             int            xsize)/* I - Width of data in pixels */
879 {
880   int                   length, /* Length of output line */
881                         count,  /* Number of repeated/non-repeated pixels */
882                         i,      /* Looping var */
883                         x;      /* Looping var */
884   unsigned short        *start, /* Start of sequence */
885                         repeat; /* Repeated pixel */
886 
887 
888   for (x = xsize, length = 0; x > 0;)
889   {
890     start = row;
891     row   += 2;
892     x     -= 2;
893 
894     while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0]))
895     {
896       row ++;
897       x --;
898     };
899 
900     row -= 2;
901     x   += 2;
902 
903     count = row - start;
904     while (count > 0)
905     {
906       i     = count > 126 ? 126 : count;
907       count -= i;
908 
909       if (putshort(128 | i, sgip) == EOF)
910         return (-1);
911       length ++;
912 
913       while (i > 0)
914       {
915         if (putshort(*start, sgip) == EOF)
916           return (-1);
917         start ++;
918         i --;
919         length ++;
920       };
921     };
922 
923     if (x <= 0)
924       break;
925 
926     start  = row;
927     repeat = row[0];
928 
929     row ++;
930     x --;
931 
932     while (x > 0 && *row == repeat)
933     {
934       row ++;
935       x --;
936     };
937 
938     count = row - start;
939     while (count > 0)
940     {
941       i     = count > 126 ? 126 : count;
942       count -= i;
943 
944       if (putshort(i, sgip) == EOF)
945         return (-1);
946       length ++;
947 
948       if (putshort(repeat, sgip) == EOF)
949         return (-1);
950       length ++;
951     };
952   };
953 
954   length ++;
955 
956   if (putshort(0, sgip) == EOF)
957     return (-1);
958   else
959     return (2 * length);
960 }
961