1 // Copyright (c) 2005-2008 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
2 // All rights reserved.
3 //
4 // This file is part of the ImageIO Library, and as been adapted for CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/CGAL_ImageIO/include/CGAL/ImageIO/gif_impl.h $
7 // $Id: gif_impl.h bdecbc9 2020-10-16T10:47:54+02:00 Raphael Grimm
8 // SPDX-License-Identifier: LGPL-3.0-or-later
9 //
10 //
11 // Author(s)     :  ASCLEPIOS Project (INRIA Sophia-Antipolis), Laurent Rineau
12 
13 #ifdef CGAL_HEADER_ONLY
14 #define CGAL_INLINE_FUNCTION inline
15 #else
16 #define CGAL_INLINE_FUNCTION
17 #endif
18 
19 #include <string.h>
20 
21 #ifdef WIN32
22 #include <io.h>
23 #endif
24 
25 #ifdef CGAL_HEADER_ONLY
26 
27   #define CGAL_GLOBAL_STATE_VAR(TYPE, NAME, VALUE)  \
28     inline TYPE & get_static_##NAME()               \
29     {                                               \
30       static TYPE NAME = VALUE;                     \
31       return NAME;                                  \
32     }
33 
34 #else // CGAL_HEADER_ONLY
35 
36   #define CGAL_GLOBAL_STATE_VAR(TYPE, NAME, VALUE)  \
37     TYPE NAME;                                      \
38     inline TYPE& get_static_##NAME()                \
39     {                                               \
40       return NAME;                                  \
41     }
42 
43 #endif // CGAL_HEADER_ONLY
44 
45 
46 /** Magic header for GIF files */
47 #define GIF_MAGIC "GIF8"
48 
49 
50 
51 typedef unsigned char byte;
52 #define TRUE 1
53 #define FALSE 0
54 
55 #define NEXTBYTE      (*ptr++)
56 #define EXTENSION     0x21
57 #define IMAGESEP      0x2c
58 #define TRAILER       0x3b
59 #define INTERLACEMASK 0x40
60 #define COLORMAPMASK  0x80
61 
62 
63 #define CGAL_GIF_IMPL_DEBUG 0
64 
65 //FILE *fp;
66 //int   gif89 = 0;
67 static const char *id87 = "GIF87a";
68 static const char *id89 = "GIF89a";
69 
70 static int EGApalette[16][3] = {
71   {0,0,0},       {0,0,128},     {0,128,0},     {0,128,128},
72   {128,0,0},     {128,0,128},   {128,128,0},   {200,200,200},
73   {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255},
74   {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} };
75 
76 
77 static int  ReadCode();
78 static void DoInterlace(byte);
79 static int GifError(const char *);
80 
CGAL_GLOBAL_STATE_VAR(byte *,Raster,nullptr)81 CGAL_GLOBAL_STATE_VAR(byte *, Raster, nullptr) /* The raster data stream, unblocked */
82 CGAL_GLOBAL_STATE_VAR(byte *, RawGIF, nullptr)
83 CGAL_GLOBAL_STATE_VAR(byte *, r, nullptr)
84 CGAL_GLOBAL_STATE_VAR(byte *, g, nullptr)
85 CGAL_GLOBAL_STATE_VAR(byte *, b, nullptr)     /* The colormap */
86 CGAL_GLOBAL_STATE_VAR(int, BitOffset, 0)    /* Bit Offset of next code */
87 CGAL_GLOBAL_STATE_VAR(int, XC, 0)
88 CGAL_GLOBAL_STATE_VAR(int, YC, 0)            /* Output X and Y coords of current pixel */
89 CGAL_GLOBAL_STATE_VAR(int, CodeSize, 0)            /* Code size, read from GIF header */
90 CGAL_GLOBAL_STATE_VAR(int, ReadMask, 0)     /* Code AND mask for current code size */
91 CGAL_GLOBAL_STATE_VAR(int, Pass, 0)            /* Used by output routine if interlaced pic */
92 CGAL_GLOBAL_STATE_VAR(int, Width, 0)
93 CGAL_GLOBAL_STATE_VAR(int, Height, 0)       /* image dimensions */
94 CGAL_GLOBAL_STATE_VAR(unsigned char *, org, nullptr)
95 CGAL_GLOBAL_STATE_VAR(unsigned char *, buf, nullptr)
96 
97 CGAL_INLINE_FUNCTION
98 int testGifHeader(char *magic,const char *) {
99   if (!strcmp(magic, GIF_MAGIC))
100     return 0;
101   else
102     return -1;
103 }
104 CGAL_INLINE_FUNCTION
createGifFormat()105 PTRIMAGE_FORMAT createGifFormat() {
106   PTRIMAGE_FORMAT f=(PTRIMAGE_FORMAT) ImageIO_alloc(sizeof(IMAGE_FORMAT));
107 
108   f->testImageFormat=&testGifHeader;
109   f->readImageHeader=&readGifImage;
110   f->writeImage=0;
111   strcpy(f->fileExtension,".gif");
112   strcpy(f->realName,"Gif");
113   return f;
114 }
115 
116 CGAL_INLINE_FUNCTION
use(int)117 void use(int) {} // warning killer
118 
119 /*****************************/
120 CGAL_INLINE_FUNCTION
readGifImage(const char * name,_image * im)121 int readGifImage(const char *name,_image *im) {
122 FILE *fp;
123 int   gif89 = 0;
124 
125   byte ch, ch1;
126   byte *ptr, *ptr1;
127   int i, block;
128   int npixels, maxpixels, aspect;
129   float normaspect;
130   int OutCount = 0,                /* Decompressor output 'stack count' */
131     RWidth, RHeight,                /* screen dimensions */
132     /*LeftOfs, TopOfs,                 image offset */
133     BitsPerPixel,                /* Bits per pixel, read from GIF header */
134     ColorMapSize,                /* number of colors */
135     Background,                         /* background color */
136     InitCodeSize,                /* Starting code size, used during Clear */
137     Code,                        /* Value returned by ReadCode */
138     MaxCode,                        /* limiting value for current code size */
139     ClearCode,                        /* GIF clear code */
140     EOFCode,                        /* GIF end-of-information code */
141     CurCode, OldCode=0, InCode,        /* Decompressor variables */
142     FirstFree,                        /* First free code, generated per GIF spec */
143     FreeCode,                        /* Decompressor,next free slot in hash table */
144     FinChar=0,                        /* Decompressor variable */
145     BitMask,                        /* AND mask for data size */
146     Misc;                       /* miscellaneous bits (interlace, local cmap)*/
147   int Interlace, HasColormap;
148   /* not used
149    */
150   /* char header[10]; */
151 
152   /* The hash table used by the decompressor */
153   int Prefix[4096];
154   int Suffix[4096];
155   /* An output array used by the decompressor */
156   int OutCode[4097];
157 
158   /* initialize variables */
159   get_static_BitOffset() =
160     get_static_XC() =
161     get_static_YC() =
162     get_static_Pass() =
163     OutCount =
164     npixels =
165     maxpixels = 0;
166   get_static_RawGIF() = get_static_Raster() = nullptr;
167   gif89 = 0;
168 
169 #ifdef WIN32
170  fp = fopen(name,"rb");
171 #else
172   fp = fopen(name,"r");
173 #endif
174   fp = fopen(name,"rb");
175   if (!fp) {
176     return(GifError("could not open a GIF file"));
177   }
178   /* find the size of the file */
179   fseek(fp, 0L, 2);
180   long filesize = ftell(fp);
181   fseek(fp, 0L, 0);
182 
183  /* the +256's are so we can read truncated GIF files without fear of
184      segmentation violation */
185   if (!(ptr = get_static_RawGIF() = (byte *) ImageIO_alloc(filesize+256)))
186     return( GifError("not enough memory to read gif file") );
187 
188   if (!(get_static_Raster() = (byte *) ImageIO_alloc(filesize+256)))
189     return( GifError("not enough memory to read gif file") );
190 
191   if (fread(ptr, filesize, 1, fp) != 1)
192     return( GifError("GIF data read failed") );
193    if      (strncmp((char *) ptr, id87, 6)==0) gif89 = 0;
194   else if (strncmp((char *) ptr, id89, 6)==0) gif89 = 1;
195   else    return( GifError("not a GIF file"));
196 
197   ptr += 6;
198  /* Get variables from the GIF screen descriptor */
199 
200   ch = NEXTBYTE;
201   RWidth = ch + 0x100 * NEXTBYTE;        /* screen dimensions... not used. */
202   ch = NEXTBYTE;
203   RHeight = ch + 0x100 * NEXTBYTE;
204   use(RWidth);
205   use(RHeight);
206 
207   ch = NEXTBYTE;
208   HasColormap = ((ch & COLORMAPMASK) ? TRUE : FALSE);
209 
210   BitsPerPixel = (ch & 7) + 1;
211   ColorMapSize = 1 << BitsPerPixel;
212   BitMask = ColorMapSize - 1;
213 
214   Background = NEXTBYTE;                /* background color... not used. */
215   use(Background);
216 
217 
218   aspect = NEXTBYTE;
219   if (aspect) {
220     if (!gif89) return(GifError("corrupt GIF file (screen descriptor)"));
221     else normaspect = (float) (aspect + 15) / 64.0f;   /* gif89 aspect ratio */
222     if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect);
223   }
224 
225 
226   /* Read in global colormap. */
227   if (HasColormap)
228     {
229       get_static_r() = (byte *) ImageIO_alloc(ColorMapSize * sizeof(byte));
230       get_static_g() = (byte *) ImageIO_alloc(ColorMapSize * sizeof(byte));
231       get_static_b() = (byte *) ImageIO_alloc(ColorMapSize * sizeof(byte));
232 
233       for (i = 0; i < ColorMapSize; i++) {
234         get_static_r()[i] = NEXTBYTE;
235         get_static_g()[i] = NEXTBYTE;
236         get_static_b()[i] = NEXTBYTE;
237       }
238     }
239   else {
240     /* no colormap in GIF file */
241     /* put std EGA palette (repeated 16 times) into colormap, for lack of
242        anything better to do */
243     ColorMapSize = 256;
244     get_static_r() = (byte *) ImageIO_alloc(256 * sizeof(byte));
245     get_static_g() = (byte *) ImageIO_alloc(256 * sizeof(byte));
246     get_static_b() = (byte *) ImageIO_alloc(256 * sizeof(byte));
247 
248     for (i = 0; i < 256; i++) {
249       get_static_r()[i] = byte(EGApalette[i&15][0]);
250       get_static_g()[i] = byte(EGApalette[i&15][1]);
251       get_static_b()[i] = byte(EGApalette[i&15][2]);
252     }
253   }
254 
255   /* possible things at this point are:
256    *   an application extension block
257    *   a comment extension block
258    *   an (optional) graphic control extension block
259    *       followed by either an image
260    *           or a plaintext extension
261    */
262   while (1) {
263     block = NEXTBYTE;
264 
265     if (block == EXTENSION) {  /* parse extension blocks */
266       int i, fn, blocksize, aspnum, aspden;
267 
268       /* read extension block */
269       fn = NEXTBYTE;
270 
271       if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF extension type 0x%02x\n", fn);
272 
273       if (fn == 'R') {                  /* GIF87 aspect extension */
274         blocksize = NEXTBYTE;
275         if (blocksize == 2) {
276           aspnum = NEXTBYTE;
277           aspden = NEXTBYTE;
278           if (aspden>0 && aspnum>0)
279             normaspect = (float) aspnum / (float) aspden;
280           else { normaspect = 1.0;  aspnum = aspden = 1; }
281 
282           if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF87 aspect extension: %d:%d = %f\n\n",
283                              aspnum, aspden,normaspect);
284         }
285         else {
286           for (i=0; i<blocksize; i++) (void)NEXTBYTE;
287         }
288       }
289 
290       else if (fn == 0xFE) {  /* Comment Extension.  just eat it */
291         int ch, j, sbsize;
292 
293         if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"Comment extension:  ");
294         /* read (and ignore) data sub-blocks */
295         do {
296           j = 0;  sbsize = NEXTBYTE;
297           while (j<sbsize) {
298             ch = NEXTBYTE;  j++;
299             if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"%c", ch);
300           }
301         } while (sbsize);
302         if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"\n\n");
303       }
304 
305       else if (fn == 0x01) {  /* PlainText Extension */
306         int j,sbsize,ch;
307         int tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight, fg, bg;
308 
309         /*        SetISTR(ISTR_WARNING,
310                 "PlainText extension found in GIF file.  Ignored.");*/
311 
312         sbsize   = NEXTBYTE;
313         tgLeft   = NEXTBYTE;  tgLeft   += (NEXTBYTE)<<8;
314         tgTop    = NEXTBYTE;  tgTop    += (NEXTBYTE)<<8;
315         tgWidth  = NEXTBYTE;  tgWidth  += (NEXTBYTE)<<8;
316         tgHeight = NEXTBYTE;  tgHeight += (NEXTBYTE)<<8;
317         cWidth   = NEXTBYTE;
318         cHeight  = NEXTBYTE;
319         fg       = NEXTBYTE;
320         bg       = NEXTBYTE;
321         i=12;
322         for ( ; i<sbsize; i++) (void)NEXTBYTE;   /* read rest of first subblock */
323 
324         if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,
325                            "PlainText: tgrid=%d,%d %dx%d  cell=%dx%d  col=%d,%d\n",
326                            tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight,
327                            fg, bg);
328 
329         /* read (and ignore) data sub-blocks */
330         do {
331           j = 0;
332           sbsize = NEXTBYTE;
333           while (j<sbsize) {
334             ch = NEXTBYTE;  j++;
335             if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"%c", ch);
336           }
337         } while (sbsize);
338         if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"\n\n");
339       }
340 
341 
342       else if (fn == 0xF9) {  /* Graphic Control Extension */
343         int j, sbsize;
344 
345         if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"Graphic Control extension\n\n");
346 
347         /*        SetISTR(ISTR_WARNING,
348                 "Graphic Control Extension in GIF file.  Ignored.");*/
349 
350         /* read (and ignore) data sub-blocks */
351         do {
352           j = 0; sbsize = NEXTBYTE;
353           while (j<sbsize) { (void)NEXTBYTE;  j++; }
354         } while (sbsize);
355       }
356 
357 
358       else { /* unknown extension */
359         int j, sbsize;
360 
361         if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"unknown GIF extension 0x%02x\n\n", fn);
362 
363         /*        SetISTR(ISTR_WARNING,
364                 "Unknown extension 0x%02x in GIF file.  Ignored.",fn);*/
365 
366         /* read (and ignore) data sub-blocks */
367         do {
368           j = 0; sbsize = NEXTBYTE;
369           while (j<sbsize) { (void)NEXTBYTE;  j++; }
370         } while (sbsize);
371       }
372     }
373 
374     else if (block == IMAGESEP) break;   /* read an image */
375 
376     else if (block == TRAILER) {
377       return( GifError("no image data found in GIF file") );
378     }
379 
380     else return (GifError("Unknown block type found in file."));
381   }
382 
383 
384   /* read in values from the image descriptor */
385   ch = NEXTBYTE;
386   /* LeftOfs = ch + 0x100 * NEXTBYTE;*/
387   ch = NEXTBYTE;
388   /* TopOfs = ch + 0x100 * NEXTBYTE; */
389   ch = NEXTBYTE;
390   ch = NEXTBYTE;
391   ch = NEXTBYTE;
392   get_static_Width() = ch + 0x100 * NEXTBYTE;
393   ch = NEXTBYTE;
394   get_static_Height() = ch + 0x100 * NEXTBYTE;
395 
396   Misc = NEXTBYTE;
397   Interlace = ((Misc & INTERLACEMASK) ? TRUE : FALSE);
398 
399   if (Misc & 0x80) {
400     for (i=0; i< 1 << ((Misc&7)+1); i++) {
401       get_static_r()[i] = NEXTBYTE;
402       get_static_g()[i] = NEXTBYTE;
403       get_static_b()[i] = NEXTBYTE;
404     }
405   }
406 
407 
408   if (!HasColormap && !(Misc&0x80)) {
409     /* no global or local colormap */
410     /*    SetISTR(ISTR_WARNING,
411           "No colormap in this GIF file.  Assuming EGA colors.");*/
412   }
413 
414 
415 
416   /* Start reading the raster data. First we get the intial code size
417    * and compute decompressor constant values, based on this code size.
418    */
419 
420   /*  SetISTR(ISTR_FORMAT, "GIF%s, %d bits per pixel, %sinterlaced.  (%d bytes)",
421       (gif89) ? "89" : "87", BitsPerPixel,
422       Interlace ? "" : "non-", filesize);*/
423 
424   get_static_CodeSize() = NEXTBYTE;
425 
426   ClearCode = (1 << get_static_CodeSize());
427   EOFCode = ClearCode + 1;
428   FreeCode = FirstFree = ClearCode + 2;
429 
430   /* The GIF spec has it that the code size is the code size used to
431    * compute the above values is the code size given in the file, but the
432    * code size used in compression/decompression is the code size given in
433    * the file plus one. (thus the ++).
434    */
435   get_static_CodeSize()++;
436   InitCodeSize = get_static_CodeSize();
437   MaxCode = (1 << get_static_CodeSize());
438   get_static_ReadMask() = MaxCode - 1;
439 
440   /* UNBLOCK:
441    * Read the raster data.  Here we just transpose it from the GIF array
442    * to the Raster array, turning it from a series of blocks into one long
443    * data stream, which makes life much easier for ReadCode().
444    */
445 
446   ptr1 = get_static_Raster();
447   do {
448     ch = ch1 = NEXTBYTE;
449     while (ch--) {
450                 *ptr1 = NEXTBYTE;
451                 ptr1++; }
452     if ((ptr - get_static_RawGIF()) > filesize) {
453       /*      SetISTR(ISTR_WARNING,
454               "This GIF file seems to be truncated.  Winging it.");*/
455       break;
456     }
457   } while(ch1);
458   ImageIO_free(get_static_RawGIF());  get_static_RawGIF() = nullptr;
459 
460 
461   if (CGAL_GIF_IMPL_DEBUG) {
462     fprintf(stderr,"xv: LoadGIF() - picture is %dx%d, %d bits, %sinterlaced\n",
463             get_static_Width(), get_static_Height(), BitsPerPixel, Interlace ? "" : "non-");
464   }
465 
466 
467   /* Allocate the 'pic' */
468   maxpixels = get_static_Width()*get_static_Height();
469   im->xdim = get_static_Width();
470   im->ydim = get_static_Height();
471   im->zdim = 1;
472   im->vdim = 3;
473   im->wdim = 1;
474   im->wordKind = WK_FIXED;
475   im->sign = SGN_UNSIGNED;
476   im->data = ImageIO_alloc(get_static_Width() * get_static_Height() * 3);
477   get_static_org() = get_static_buf() = (unsigned char *) im->data;
478 
479   if (!get_static_org())
480     return( GifError("not enough memory for image buffer") );
481 
482 
483   /* Decompress the file, continuing until you see the GIF EOF code.
484    * One obvious enhancement is to add checking for corrupt files here.
485    */
486   Code = ReadCode();
487   while (Code != EOFCode) {
488    /* Clear code sets everything back to its initial value, then reads the
489      * immediately subsequent code as uncompressed data.
490      */
491 
492           if (Code == ClearCode) {
493       get_static_CodeSize() = InitCodeSize;
494       MaxCode = (1 << get_static_CodeSize());
495       get_static_ReadMask() = MaxCode - 1;
496       FreeCode = FirstFree;
497       Code = ReadCode();
498       CurCode = OldCode = Code;
499       FinChar = CurCode & BitMask;
500       if (!Interlace) {
501         *get_static_buf()++ = get_static_r()[FinChar];
502         *get_static_buf()++ = get_static_g()[FinChar];
503         *get_static_buf()++ = get_static_b()[FinChar];
504       }
505       else DoInterlace((byte)FinChar);
506       npixels++;
507     }
508 
509     else {
510       /* If not a clear code, must be data: save same as CurCode and InCode */
511 
512       /* if we're at maxcode and didn't get a clear, stop loading */
513       if (FreeCode>=4096) {
514                   printf("freecode blew up\n");
515               break;
516           }
517 
518       CurCode = InCode = Code;
519 
520       /* If greater or equal to FreeCode, not in the hash table yet;
521        * repeat the last character decoded
522        */
523 
524       if (CurCode >= FreeCode) {
525         CurCode = OldCode;
526         if (OutCount > 4096) {
527                 printf("outcount1 blew up\n");  break; }
528         OutCode[OutCount++] = FinChar;
529       }
530 
531       /* Unless this code is raw data, pursue the chain pointed to by CurCode
532        * through the hash table to its end; each code in the chain puts its
533        * associated output code on the output queue.
534        */
535 
536       while (CurCode > BitMask) {
537                   if (OutCount > 4096) {
538                           fprintf(stderr,"outcount2 blew up\n"); break;}   /* corrupt file */
539         OutCode[OutCount++] = Suffix[CurCode];
540         CurCode = Prefix[CurCode];
541       }
542 
543       if (OutCount > 4096) {
544                   printf("outcount blew up\n");  break; }
545 
546       /* The last code in the chain is treated as raw data. */
547 
548       FinChar = CurCode & BitMask;
549       OutCode[OutCount++] = FinChar;
550 
551       /* Now we put the data out to the Output routine.
552        * It's been stacked LIFO, so deal with it that way...
553        */
554 
555       /* safety thing:  prevent exceeding range of 'pic' */
556       if (npixels + OutCount > maxpixels) OutCount = maxpixels-npixels;
557 
558       npixels += OutCount;
559       if (!Interlace) for (i=OutCount-1; i>=0; i--) {
560           *get_static_buf()++ = get_static_r()[OutCode[i]];
561           *get_static_buf()++ = get_static_g()[OutCode[i]];
562           *get_static_buf()++ = get_static_b()[OutCode[i]];
563       }
564       else  for (i=OutCount-1; i>=0; i--) DoInterlace((byte)OutCode[i]);
565       OutCount = 0;
566 
567       /* Build the hash table on-the-fly. No table is stored in the file. */
568 
569       Prefix[FreeCode] = OldCode;
570       Suffix[FreeCode] = FinChar;
571       OldCode = InCode;
572 
573       /* Point to the next slot in the table.  If we exceed the current
574        * MaxCode value, increment the code size unless it's already 12.  If it
575        * is, do nothing: the next code decompressed better be CLEAR
576        */
577 
578       FreeCode++;
579       if (FreeCode >= MaxCode) {
580         if (get_static_CodeSize() < 12) {
581           get_static_CodeSize()++;
582           MaxCode *= 2;
583           get_static_ReadMask() = (1 << get_static_CodeSize()) - 1;
584         }
585       }
586     }
587     Code = ReadCode();
588     if (npixels >= maxpixels) break;
589   }
590   ImageIO_free(get_static_Raster());  get_static_Raster() = nullptr;
591 
592   if (npixels != maxpixels) {
593     /*    SetISTR(ISTR_WARNING,"This GIF file seems to be truncated.  Winging it.");*/
594     if (!Interlace)
595       memset(get_static_buf(), 0, 3*(maxpixels-npixels)); /* clear to EOBuffer */
596   }
597   /*  SetDirRButt(F_FORMAT, F_GIF);
598       SetDirRButt(F_COLORS, F_FULLCOLOR);*/
599   return 1;
600 }
601 
602 
603 /* Fetch the next code from the raster data stream.  The codes can be
604  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
605  * maintain our location in the Raster array as a BIT Offset.  We compute
606  * the byte Offset into the raster array by dividing this by 8, pick up
607  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
608  * bring the desired code to the bottom, then mask it off and return it.
609  */
610 
611 CGAL_INLINE_FUNCTION
ReadCode()612 static int ReadCode()
613 {
614   int RawCode, ByteOffset;
615 
616   ByteOffset = get_static_BitOffset() / 8;
617   RawCode = get_static_Raster()[ByteOffset] + (get_static_Raster()[ByteOffset + 1] << 8);
618   if (get_static_CodeSize() >= 8)
619     RawCode += ( ((int) get_static_Raster()[ByteOffset + 2]) << 16);
620   RawCode >>= (get_static_BitOffset() % 8);
621   get_static_BitOffset() += get_static_CodeSize();
622 
623   return(RawCode & get_static_ReadMask());
624 }
625 
626 
627 /***************************/
628 CGAL_INLINE_FUNCTION
DoInterlace(byte Index)629 static void DoInterlace(byte Index) {
630   static byte *ptr = nullptr;
631   static int   oldYC = -1;
632 
633   if (oldYC != get_static_YC()) {
634     ptr = get_static_org() + 3 * get_static_YC() * get_static_Width();
635     oldYC = get_static_YC();
636   }
637 
638   if (get_static_YC() < get_static_Height()) {
639     *ptr++ = get_static_r()[Index];
640     *ptr++ = get_static_g()[Index];
641     *ptr++ = get_static_b()[Index];
642   }
643 
644   /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
645   if (++get_static_XC() == get_static_Width()) {
646 
647     /* deal with the interlace as described in the GIF
648      * spec.  Put the decoded scan line out to the screen if we haven't gone
649      * past the bottom of it
650      */
651 
652     get_static_XC() = 0;
653 
654     switch (get_static_Pass()) {
655     case 0:
656       get_static_YC() += 8;
657       if (get_static_YC() >= get_static_Height()) { get_static_Pass()++; get_static_YC() = 4; }
658       break;
659 
660     case 1:
661       get_static_YC() += 8;
662       if (get_static_YC() >= get_static_Height()) { get_static_Pass()++; get_static_YC() = 2; }
663       break;
664 
665     case 2:
666       get_static_YC() += 4;
667       if (get_static_YC() >= get_static_Height()) { get_static_Pass()++; get_static_YC() = 1; }
668       break;
669 
670     case 3:
671       get_static_YC() += 2;  break;
672 
673     default:
674       break;
675     }
676   }
677 }
678 
679 
680 
681 /*****************************/
682 CGAL_INLINE_FUNCTION
GifError(const char * st)683 static int GifError(const char *st) {
684   fprintf(stderr,"readGifImage: error: %s\n",st);
685 
686   if (get_static_RawGIF() != nullptr) ImageIO_free(get_static_RawGIF());
687   if (get_static_Raster() != nullptr) ImageIO_free(get_static_Raster());
688 
689   return -1;
690 }
691 
692 #undef CGAL_GLOBAL_STATE_VAR
693 
694