1 /*
2 * xvgif.c - GIF loading code for 'xv'. Based strongly on...
3 *
4 * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
5 *
6 * Copyright (c) 1988, 1989 by Patrick J. Naughton
7 *
8 * Author: Patrick J. Naughton
9 * naughton@wind.sun.com
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 */
24
25
26 #include "xv.h"
27
28 typedef int boolean;
29
30 #define NEXTBYTE (*dataptr++)
31 #define SKIPBYTE (dataptr++) /* quiet some compiler warnings */
32 #define EXTENSION 0x21
33 #define IMAGESEP 0x2c /* a.k.a. Image Descriptor */
34 #define TRAILER 0x3b
35 #define INTERLACEMASK 0x40
36 #define COLORMAPMASK 0x80
37
38
39
40 static FILE *fp;
41
42 static int
43 BitOffset = 0, /* Bit Offset of next code */
44 XC = 0, YC = 0, /* Output X and Y coords of current pixel */
45 Pass = 0, /* Used by output routine if interlaced pic */
46 OutCount = 0, /* Decompressor output 'stack count' */
47 RWidth, RHeight, /* screen dimensions */
48 Width, Height, /* image dimensions */
49 LeftOfs, TopOfs, /* image offset */
50 BitsPerPixel, /* Bits per pixel, read from GIF header */
51 /* BytesPerScanline, */ /* bytes per scanline in output raster */
52 ColorMapSize, /* number of colors */
53 Background, /* background color */
54 Transparent, /* transparent color (GRR 19980314) */
55 CodeSize, /* Code size, read from GIF header */
56 InitCodeSize, /* Starting code size, used during Clear */
57 Code, /* Value returned by ReadCode */
58 MaxCode, /* limiting value for current code size */
59 ClearCode, /* GIF clear code */
60 EOFCode, /* GIF end-of-information code */
61 CurCode, OldCode, InCode, /* Decompressor variables */
62 FirstFree, /* First free code, generated per GIF spec */
63 FreeCode, /* Decompressor, next free slot in hash table */
64 FinChar, /* Decompressor variable */
65 BitMask, /* AND mask for data size */
66 ReadMask, /* Code AND mask for current code size */
67 Misc, /* miscellaneous bits (interlace, local cmap)*/
68 GlobalBitsPerPixel, /* may have local colormap of different size */
69 GlobalColorMapSize, /* (ditto) */
70 GlobalBitMask; /* (ditto) */
71
72
73 static boolean Interlace, HasGlobalColormap;
74
75 static byte *RawGIF; /* The heap array to hold it, raw */
76 static byte *Raster; /* The raster data stream, unblocked */
77 static byte *pic8;
78
79 /* The hash table used by the decompressor */
80 static int Prefix[4096];
81 static int Suffix[4096];
82
83 /* An output array used by the decompressor */
84 static int OutCode[4097];
85
86 static int gif89 = 0;
87 static const char *id87 = "GIF87a";
88 static const char *id89 = "GIF89a";
89
90 static int const EGApalette[16][3] = {
91 {0,0,0}, {0,0,128}, {0,128,0}, {0,128,128},
92 {128,0,0}, {128,0,128}, {128,128,0}, {200,200,200},
93 {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255},
94 {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} };
95
96
97 static int readImage PARM((PICINFO *));
98 static int readCode PARM((void));
99 static void doInterlace PARM((int));
100 static int gifError PARM((PICINFO *, const char *));
101 static void gifWarning PARM((const char *));
102
103 static int filesize;
104 static const char *bname;
105 static byte *dataptr;
106
107
108 /*****************************/
LoadGIF(fname,pinfo)109 int LoadGIF(fname, pinfo)
110 char *fname;
111 PICINFO *pinfo;
112 /*****************************/
113 {
114 /* returns '1' if successful */
115
116 register byte ch, *origptr;
117 register int i, block;
118 int aspect;
119 char tmpname[256];
120 byte r[256], g[256], b[256];
121
122 /* initialize variables */
123 BitOffset = XC = YC = OutCount = 0;
124 Pass = -1;
125 RawGIF = Raster = pic8 = NULL;
126 gif89 = 0;
127 Transparent = -1;
128
129 pinfo->pic = (byte *) NULL;
130 pinfo->comment = (char *) NULL;
131 pinfo->numpages= 0;
132
133 bname = BaseName(fname);
134 fp = xv_fopen(fname,"r");
135 if (!fp) return ( gifError(pinfo, "can't open file") );
136
137
138 /* find the size of the file */
139 fseek(fp, 0L, 2);
140 filesize = ftell(fp);
141 fseek(fp, 0L, 0);
142
143 if (filesize + 256 < filesize)
144 return( gifError(pinfo, "GIF file size is too large") );
145
146 /* the +256's are so we can read truncated GIF files without fear of
147 segmentation violation */
148 if (!(dataptr = RawGIF = (byte *) calloc((size_t) filesize+256, (size_t) 1)))
149 FatalError("LoadGIF: not enough memory to read GIF file");
150
151 if (!(Raster = (byte *) calloc((size_t) filesize+256,(size_t) 1)))
152 FatalError("LoadGIF: not enough memory to read GIF file");
153
154 if (fread(dataptr, (size_t) filesize, (size_t) 1, fp) != 1)
155 return( gifError(pinfo, "GIF data read failed") );
156 fclose(fp);
157
158 origptr = dataptr;
159
160 if (strncmp((char *) dataptr, id87, (size_t) 6)==0) gif89 = 0;
161 else if (strncmp((char *) dataptr, id89, (size_t) 6)==0) gif89 = 1;
162 else return( gifError(pinfo, "not a GIF file"));
163
164 dataptr += 6;
165
166 /* Get variables from the GIF screen descriptor */
167
168 ch = NEXTBYTE;
169 RWidth = ch + 0x100 * NEXTBYTE; /* screen dimensions... not used. */
170 ch = NEXTBYTE;
171 RHeight = ch + 0x100 * NEXTBYTE;
172 if (DEBUG) fprintf(stderr,"GIF89 logical screen = %d x %d\n",RWidth,RHeight);
173
174 ch = NEXTBYTE;
175 HasGlobalColormap = ((ch & COLORMAPMASK) ? True : False);
176
177 /* GRR 20070318: fix decoding bug when global and local color-table sizes
178 * differ */
179 GlobalBitsPerPixel = BitsPerPixel = (ch & 7) + 1;
180 GlobalColorMapSize = ColorMapSize = numcols = 1 << BitsPerPixel;
181 GlobalBitMask = BitMask = ColorMapSize - 1;
182
183 Background = NEXTBYTE; /* background color... not used. */
184
185 aspect = NEXTBYTE;
186 if (aspect) {
187 #if 0
188 if (!gif89) return(gifError(pinfo,"corrupt GIF file (screen descriptor)"));
189 else normaspect = (float) (aspect + 15) / 64.0; /* gif89 aspect ratio */
190 #else
191 normaspect = (float) (aspect + 15) / 64.0; /* gif89 aspect ratio */
192 #endif
193 if (DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect);
194 /* FIXME: apparently this _should_ apply to all frames in a multi-image
195 * GIF (i.e., PgUp/PgDn), but it doesn't */
196 }
197
198
199 /* Read in global colormap. */
200
201 if (HasGlobalColormap)
202 for (i=0; i<ColorMapSize; i++) {
203 r[i] = NEXTBYTE;
204 g[i] = NEXTBYTE;
205 b[i] = NEXTBYTE;
206 }
207 else { /* no _global_ colormap in GIF file (but may have local one(s)) */
208 /* put std EGA palette (repeated 16 times) into colormap, for lack of
209 anything better to do at the moment */
210
211 for (i=0; i<256; i++) {
212 r[i] = EGApalette[i&15][0];
213 g[i] = EGApalette[i&15][1];
214 b[i] = EGApalette[i&15][2];
215 }
216 }
217 memcpy(pinfo->r, r, sizeof r);
218 memcpy(pinfo->g, g, sizeof g);
219 memcpy(pinfo->b, b, sizeof b);
220
221 if (DEBUG > 1) {
222 fprintf(stderr," global color table%s:\n",
223 HasGlobalColormap? "":" (repeated EGA palette)");
224 for (i=0; i<ColorMapSize; i++) {
225 fprintf(stderr," (%3d %02x,%02x,%02x)\n", i, pinfo->r[i],
226 pinfo->g[i], pinfo->b[i]);
227 }
228 }
229
230 /* possible things at this point are:
231 * an application extension block
232 * a comment extension block
233 * an (optional) graphic control extension block
234 * followed by either an image
235 * or a plaintext extension
236 */
237
238 while (1) {
239 block = NEXTBYTE;
240
241 if (DEBUG) fprintf(stderr,"LoadGIF: ");
242
243 if (block == EXTENSION) { /* parse extension blocks */
244 int i, fn, blocksize, aspnum, aspden;
245
246 /* read extension block */
247 fn = NEXTBYTE;
248
249 if (DEBUG) fprintf(stderr,"GIF extension type 0x%02x\n", fn);
250
251 if (fn == 'R') { /* GIF87 aspect extension */
252 int sbsize;
253
254 blocksize = NEXTBYTE;
255 if (blocksize == 2) {
256 aspnum = NEXTBYTE;
257 aspden = NEXTBYTE;
258 if (aspden>0 && aspnum>0)
259 normaspect = (float) aspnum / (float) aspden;
260 else { normaspect = 1.0; aspnum = aspden = 1; }
261
262 if (DEBUG) fprintf(stderr,"GIF87 aspect extension: %d:%d = %f\n\n",
263 aspnum, aspden,normaspect);
264 }
265 else {
266 for (i=0; i<blocksize; i++) SKIPBYTE;
267 }
268
269 while ((sbsize=NEXTBYTE)>0) { /* eat any following data subblocks */
270 for (i=0; i<sbsize; i++) SKIPBYTE;
271 }
272 }
273
274
275 else if (fn == 0xFE) { /* Comment Extension */
276 int ch, j, sbsize, cmtlen;
277 byte *ptr1, *cmt, *cmt1, *sp;
278
279 cmtlen = 0;
280 ptr1 = dataptr; /* remember start of comments */
281
282 /* figure out length of comment */
283 do {
284 sbsize = NEXTBYTE;
285 cmtlen += sbsize;
286 for (j=0; j<sbsize; j++) ch = NEXTBYTE;
287 } while (sbsize);
288
289
290 if (cmtlen>0) { /* build into one un-blocked comment */
291 /* this can overflow iff cmtlen == 2G - 1, but then filesize
292 * would have to be > 2GB, which was disallowed above */
293 cmt = (byte *) malloc((size_t) (cmtlen + 1));
294 if (!cmt) FatalError("LoadGIF: couldn't malloc space for comments");
295 /* else */ {
296 sp = cmt;
297 do {
298 sbsize = (*ptr1++);
299 for (j=0; j<sbsize; j++, sp++, ptr1++) *sp = *ptr1;
300 } while (sbsize);
301 *sp = '\0';
302
303 if (pinfo->comment) { /* have to strcat onto old comments */
304 cmt1 = (byte *) malloc(strlen(pinfo->comment) + cmtlen + 2);
305 if (!cmt1) {
306 free(cmt);
307 FatalError("LoadGIF: couldn't malloc space for comments");
308 }
309 /* else */ {
310 strcpy((char *) cmt1, (char *) pinfo->comment);
311 strcat((char *) cmt1, (char *) "\n");
312 strcat((char *) cmt1, (char *) cmt);
313 free(pinfo->comment);
314 free(cmt);
315 pinfo->comment = (char *) cmt1;
316 }
317 }
318 else pinfo->comment = (char *) cmt;
319 } /* if (cmt) */
320 } /* if cmtlen>0 */
321 }
322
323
324 else if (fn == 0x01) { /* PlainText Extension */
325 int j,sbsize,ch;
326 int tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight, fg, bg;
327
328 SetISTR(ISTR_INFO, "%s: %s", bname,
329 "PlainText extension found in GIF file. Ignored.");
330
331 sbsize = NEXTBYTE;
332 tgLeft = NEXTBYTE; tgLeft += (NEXTBYTE)<<8;
333 tgTop = NEXTBYTE; tgTop += (NEXTBYTE)<<8;
334 tgWidth = NEXTBYTE; tgWidth += (NEXTBYTE)<<8;
335 tgHeight = NEXTBYTE; tgHeight += (NEXTBYTE)<<8;
336 cWidth = NEXTBYTE;
337 cHeight = NEXTBYTE;
338 fg = NEXTBYTE;
339 bg = NEXTBYTE;
340 i=12;
341 for ( ; i<sbsize; i++) SKIPBYTE; /* read rest of first subblock */
342
343 if (DEBUG) fprintf(stderr,
344 "PlainText: tgrid=%d,%d %dx%d cell=%dx%d col=%d,%d\n",
345 tgLeft, tgTop, tgWidth, tgHeight, cWidth, cHeight, fg, bg);
346
347 /* read (and ignore) data sub-blocks */
348 do {
349 j = 0;
350 sbsize = NEXTBYTE;
351 while (j<sbsize) {
352 ch = NEXTBYTE; j++;
353 if (DEBUG) fprintf(stderr,"%c", ch);
354 }
355 } while (sbsize);
356 if (DEBUG) fprintf(stderr,"\n\n");
357 }
358
359
360 else if (fn == 0xF9) { /* Graphic Control Extension */
361 int j, sbsize;
362
363 if (DEBUG) fprintf(stderr,"Graphic Control extension\n\n");
364
365 SetISTR(ISTR_INFO, "%s: %s", bname,
366 "Graphic Control Extension ignored.");
367
368 /* read (and ignore) data sub-blocks, unless compositing with
369 * user-defined background */
370 do {
371 j = 0;
372 sbsize = NEXTBYTE;
373 /* GRR 19980314: get transparent index out of block */
374 if (have_imagebg && sbsize == 4 && Transparent < 0) {
375 byte packed_fields = NEXTBYTE;
376
377 j++;
378 SKIPBYTE; j++;
379 SKIPBYTE; j++;
380 if (packed_fields & 1) {
381 Transparent = NEXTBYTE;
382 j++;
383 }
384 }
385 while (j<sbsize) {
386 SKIPBYTE; j++;
387 }
388 } while (sbsize);
389 }
390
391
392 else if (fn == 0xFF) { /* Application Extension */
393 int j, sbsize;
394
395 if (DEBUG) fprintf(stderr,"Application extension\n\n");
396
397 /* read (and ignore) data sub-blocks */
398 do {
399 j = 0; sbsize = NEXTBYTE;
400 while (j<sbsize) { SKIPBYTE; j++; }
401 } while (sbsize);
402 }
403
404
405 else { /* unknown extension */
406 int j, sbsize;
407
408 if (DEBUG) fprintf(stderr,"unknown GIF extension 0x%02x\n\n", fn);
409
410 SetISTR(ISTR_INFO,
411 "%s: Unknown extension 0x%02x in GIF file. Ignored.",
412 bname, fn);
413
414 /* read (and ignore) data sub-blocks */
415 do {
416 j = 0; sbsize = NEXTBYTE;
417 while (j<sbsize) { SKIPBYTE; j++; }
418 } while (sbsize);
419 }
420 }
421
422
423 else if (block == IMAGESEP) {
424 if (DEBUG) fprintf(stderr, "imagesep (page=%d)\n", pinfo->numpages+1);
425 if (DEBUG) fprintf(stderr, " at start: offset=0x%lx\n",
426 (unsigned long)(dataptr-RawGIF));
427
428 BitOffset = XC = YC = Pass = OutCount = 0;
429
430 if (pinfo->numpages > 0) { /* do multipage stuff */
431 if (pinfo->numpages == 1) { /* first time only... */
432 xv_mktemp(pinfo->pagebname, "xvpgXXXXXX"); // a.k.a. close(mkstemp())
433 if (pinfo->pagebname[0] == '\0') {
434 ErrPopUp("LoadGIF: Unable to create temporary filename???",
435 "\nHow unlikely!");
436 return 0;
437 }
438 /* GRR 20070328: basename file doesn't go away, at least on Linux
439 * (though all appended-number ones do); ergo, open for reading (see
440 * if it's there), close, and explicitly unlink() if necessary */
441 /* GRR 20070506: could/should call KillPageFiles() (xv.c) instead */
442 fp = xv_fopen(pinfo->pagebname, "r");
443 if (fp) {
444 fclose(fp);
445 unlink(pinfo->pagebname); /* no errors during testing */
446 }
447 }
448 sprintf(tmpname, "%s%d", pinfo->pagebname, pinfo->numpages);
449 fp = xv_fopen(tmpname, "w");
450 if (!fp) {
451 ErrPopUp("LoadGIF: Unable to open temp file", "\nDang!");
452 return 0;
453 }
454 if (WriteGIF(fp, pinfo->pic, pinfo->type, pinfo->w, pinfo->h, pinfo->r,
455 pinfo->g, pinfo->b, numcols, pinfo->colType, NULL)) {
456 fclose(fp);
457 ErrPopUp("LoadGIF: Error writing temp file", "\nBummer!");
458 return 0;
459 }
460 fclose(fp);
461 free(pinfo->pic);
462 pinfo->pic = (byte *) NULL;
463 if (HasGlobalColormap) {
464 memcpy(pinfo->r, r, sizeof r);
465 memcpy(pinfo->g, g, sizeof g);
466 memcpy(pinfo->b, b, sizeof b);
467 }
468 BitsPerPixel = GlobalBitsPerPixel;
469 numcols = ColorMapSize = GlobalColorMapSize;
470 BitMask = GlobalBitMask;
471 }
472 if (readImage(pinfo)) ++pinfo->numpages;
473 if (DEBUG) fprintf(stderr, " at end: offset=0x%lx\n",
474 (unsigned long)(dataptr-RawGIF));
475 }
476
477
478 else if (block == TRAILER) { /* stop reading blocks */
479 if (DEBUG) fprintf(stderr,"trailer");
480 break;
481 }
482
483 else { /* unknown block type */
484 char str[128];
485
486 if (DEBUG) fprintf(stderr,"block type 0x%02x ", block);
487
488 /* don't mention bad block if file was trunc'd, as it's all bogus */
489 if ((dataptr - origptr) < filesize) {
490 sprintf(str, "Unknown block type (0x%02x) at offset 0x%lx",
491 block, (unsigned long)(dataptr - origptr) - 1);
492
493 if (!pinfo->numpages) return gifError(pinfo, str);
494 else gifWarning(str);
495 }
496
497 break;
498 }
499
500 if (DEBUG) fprintf(stderr,"\n");
501 }
502
503 free(RawGIF); RawGIF = NULL;
504 free(Raster); Raster = NULL;
505
506 if (!pinfo->numpages)
507 return( gifError(pinfo, "no image data found in GIF file") );
508 if (pinfo->numpages > 1) {
509 /* write the last page temp file */
510 int numpages = pinfo->numpages;
511 char *comment = pinfo->comment;
512 sprintf(tmpname, "%s%d", pinfo->pagebname, pinfo->numpages);
513 fp = xv_fopen(tmpname, "w");
514 if (!fp) {
515 ErrPopUp("LoadGIF: Unable to open temp file", "\nDang!");
516 return 0;
517 }
518 if (WriteGIF(fp, pinfo->pic, pinfo->type, pinfo->w, pinfo->h, pinfo->r,
519 pinfo->g, pinfo->b, numcols, pinfo->colType, NULL)) {
520 fclose(fp);
521 ErrPopUp("LoadGIF: Error writing temp file", "\nBummer!");
522 return 0;
523 }
524 fclose(fp);
525 free(pinfo->pic);
526 pinfo->pic = (byte *) NULL;
527
528 /* load the first page temp file */
529 sprintf(tmpname, "%s%d", pinfo->pagebname, 1);
530 i = LoadGIF(tmpname, pinfo);
531 pinfo->numpages = numpages;
532 pinfo->comment = comment;
533 }
534
535 return 1;
536 }
537
538
539 /********************************************/
readImage(pinfo)540 static int readImage(pinfo)
541 PICINFO *pinfo;
542 {
543 register byte ch, ch1, *ptr1, *picptr;
544 int i, npixels, maxpixels;
545 boolean HasLocalColormap;
546
547 npixels = maxpixels = 0;
548
549 /* read in values from the image descriptor */
550
551 ch = NEXTBYTE;
552 LeftOfs = ch + 0x100 * NEXTBYTE;
553 ch = NEXTBYTE;
554 TopOfs = ch + 0x100 * NEXTBYTE;
555 ch = NEXTBYTE;
556 Width = ch + 0x100 * NEXTBYTE;
557 ch = NEXTBYTE;
558 Height = ch + 0x100 * NEXTBYTE;
559
560 Misc = NEXTBYTE;
561 Interlace = ((Misc & INTERLACEMASK) ? True : False);
562 HasLocalColormap = ((Misc & COLORMAPMASK) ? True : False);
563
564 if (HasLocalColormap) {
565 BitsPerPixel = (Misc & 7) + 1;
566 ColorMapSize = numcols = 1 << BitsPerPixel; /* GRR 20070318 */
567 BitMask = ColorMapSize - 1;
568 if (DEBUG) fprintf(stderr," local color table, %d bits (%d entries)\n",
569 (Misc&7)+1, ColorMapSize);
570 for (i=0; i<ColorMapSize; i++) {
571 pinfo->r[i] = NEXTBYTE;
572 pinfo->g[i] = NEXTBYTE;
573 pinfo->b[i] = NEXTBYTE;
574 }
575 if (DEBUG > 1) {
576 for (i=0; i<ColorMapSize; i++) {
577 fprintf(stderr," (%3d %02x,%02x,%02x)\n", i, pinfo->r[i],
578 pinfo->g[i], pinfo->b[i]);
579 }
580 }
581 }
582
583
584 if (!HasGlobalColormap && !HasLocalColormap) {
585 /* no global or local colormap */
586 SetISTR(ISTR_WARNING, "%s: %s", bname,
587 "No colormap in this GIF file. Assuming EGA colors.");
588 }
589
590
591 /* GRR 19980314 */
592 /* need not worry about size of EGA palette: full 256 colors */
593 if (have_imagebg && Transparent >= 0 &&
594 Transparent < ((Misc&0x80)? (1 << ((Misc&7)+1)) : ColorMapSize) )
595 {
596 pinfo->r[Transparent] = (imagebgR >> 8);
597 pinfo->g[Transparent] = (imagebgG >> 8);
598 pinfo->b[Transparent] = (imagebgB >> 8);
599 }
600
601
602
603 /* Start reading the raster data. First we get the intial code size
604 * and compute decompressor constant values, based on this code size.
605 */
606
607 CodeSize = NEXTBYTE;
608
609 ClearCode = (1 << CodeSize);
610 EOFCode = ClearCode + 1;
611 FreeCode = FirstFree = ClearCode + 2;
612
613 /* The GIF spec has it that the code size is the code size used to
614 * compute the above values is the code size given in the file, but the
615 * code size used in compression/decompression is the code size given in
616 * the file plus one. (thus the ++).
617 */
618
619 CodeSize++;
620 InitCodeSize = CodeSize;
621 MaxCode = (1 << CodeSize);
622 ReadMask = MaxCode - 1;
623
624
625
626 /* UNBLOCK:
627 * Read the raster data. Here we just transpose it from the GIF array
628 * to the Raster array, turning it from a series of blocks into one long
629 * data stream, which makes life much easier for readCode().
630 */
631
632 ptr1 = Raster;
633 do {
634 ch = ch1 = NEXTBYTE;
635 while (ch--) { *ptr1 = NEXTBYTE; ptr1++; }
636 if ((dataptr - RawGIF) > filesize) {
637 SetISTR(ISTR_WARNING,"%s: %s", bname,
638 "This GIF file seems to be truncated. Winging it.");
639 break;
640 }
641 } while(ch1);
642
643
644
645
646 if (DEBUG) {
647 fprintf(stderr,"LoadGIF: image is %dx%d, %d bits, %sinterlaced\n",
648 Width, Height, BitsPerPixel, Interlace ? "" : "non-");
649 }
650
651
652 /* Allocate the 'pic' */
653 maxpixels = Width*Height; /* 65535*65535 max (but everything is int) */
654 if (Width <= 0 || Height <= 0 || maxpixels/Width != Height)
655 return( gifError(pinfo, "image dimensions out of range") );
656 picptr = pic8 = (byte *) malloc((size_t) maxpixels);
657 if (!pic8) FatalError("LoadGIF: couldn't malloc 'pic8'");
658
659
660
661 /* Decompress the file, continuing until you see the GIF EOF code.
662 * One obvious enhancement is to add checking for corrupt files here.
663 */
664
665 Code = readCode();
666 while (Code != EOFCode) {
667 /* Clear code sets everything back to its initial value, then reads the
668 * immediately subsequent code as uncompressed data.
669 */
670
671 if (Code == ClearCode) {
672 CodeSize = InitCodeSize;
673 MaxCode = (1 << CodeSize);
674 ReadMask = MaxCode - 1;
675 FreeCode = FirstFree;
676 Code = readCode();
677 CurCode = OldCode = Code;
678 FinChar = CurCode & BitMask;
679 if (!Interlace) *picptr++ = FinChar;
680 else doInterlace(FinChar);
681 npixels++;
682 }
683 else {
684 /* If not a clear code, must be data: save same as CurCode and InCode */
685
686 /* if we're at maxcode and didn't get a clear, stop loading */
687 if (FreeCode>=4096) { /* printf("freecode blew up\n"); */
688 break; }
689
690 CurCode = InCode = Code;
691
692 /* If greater or equal to FreeCode, not in the hash table yet;
693 * repeat the last character decoded
694 */
695
696 if (CurCode >= FreeCode) {
697 CurCode = OldCode;
698 if (OutCount > 4096) { /* printf("outcount1 blew up\n"); */ break; }
699 OutCode[OutCount++] = FinChar;
700 }
701
702 /* Unless this code is raw data, pursue the chain pointed to by CurCode
703 * through the hash table to its end; each code in the chain puts its
704 * associated output code on the output queue.
705 */
706
707 while (CurCode >= ClearCode) { /* Joe Zbiciak fix, 20070621 */
708 if (OutCount > 4096) break; /* corrupt file */
709 OutCode[OutCount++] = Suffix[CurCode];
710 CurCode = Prefix[CurCode];
711 }
712
713 if (OutCount > 4096) { /* printf("outcount blew up\n"); */ break; }
714
715 /* The last code in the chain is treated as raw data. */
716
717 FinChar = CurCode & BitMask;
718 OutCode[OutCount++] = FinChar;
719
720 /* Now we put the data out to the Output routine.
721 * It's been stacked LIFO, so deal with it that way...
722 */
723
724 /* safety thing: prevent exceeding range of 'pic8' */
725 if (npixels + OutCount > maxpixels) OutCount = maxpixels-npixels;
726
727 npixels += OutCount;
728 if (!Interlace) for (i=OutCount-1; i>=0; i--) *picptr++ = OutCode[i];
729 else for (i=OutCount-1; i>=0; i--) doInterlace(OutCode[i]);
730 OutCount = 0;
731
732 /* Build the hash table on-the-fly. No table is stored in the file. */
733
734 Prefix[FreeCode] = OldCode;
735 Suffix[FreeCode] = FinChar;
736 OldCode = InCode;
737
738 /* Point to the next slot in the table. If we exceed the current
739 * MaxCode value, increment the code size unless it's already 12. If it
740 * is, do nothing: the next code decompressed better be CLEAR
741 */
742
743 FreeCode++;
744 if (FreeCode >= MaxCode) {
745 if (CodeSize < 12) {
746 CodeSize++;
747 MaxCode *= 2;
748 ReadMask = (1 << CodeSize) - 1;
749 }
750 }
751 }
752 Code = readCode();
753 if (npixels >= maxpixels) break;
754 }
755
756 if (npixels != maxpixels) {
757 SetISTR(ISTR_WARNING,"%s: %s", bname,
758 "This GIF file seems to be truncated. Winging it.");
759 if (!Interlace) /* clear->EOBuffer */
760 xvbzero((char *) pic8+npixels,
761 (size_t) (maxpixels-npixels<0 ? 0 : maxpixels-npixels));
762 }
763
764 /* fill in the PICINFO structure */
765
766 pinfo->pic = pic8;
767 pinfo->w = Width;
768 pinfo->h = Height;
769 pinfo->type = PIC8;
770 pinfo->frmType = F_GIF;
771 pinfo->colType = F_FULLCOLOR;
772
773 pinfo->normw = pinfo->w; pinfo->normh = pinfo->h;
774
775 sprintf(pinfo->fullInfo,
776 "GIF%s, %d bit%s per pixel, %sinterlaced. (%d bytes)",
777 (gif89) ? "89" : "87", BitsPerPixel,
778 (BitsPerPixel==1) ? "" : "s",
779 Interlace ? "" : "non-", filesize);
780
781 sprintf(pinfo->shrtInfo, "%dx%d GIF%s.",Width,Height,(gif89) ? "89" : "87");
782
783 /* pinfo.comment gets handled in main LoadGIF() block-reader */
784
785 return 1;
786 }
787
788
789
790 /* Fetch the next code from the raster data stream. The codes can be
791 * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
792 * maintain our location in the Raster array as a BIT Offset. We compute
793 * the byte Offset into the raster array by dividing this by 8, pick up
794 * three bytes, compute the bit Offset into our 24-bit chunk, shift to
795 * bring the desired code to the bottom, then mask it off and return it.
796 */
797
readCode()798 static int readCode()
799 {
800 int RawCode, ByteOffset;
801
802 ByteOffset = BitOffset / 8;
803 RawCode = Raster[ByteOffset] + (Raster[ByteOffset + 1] << 8);
804 if (CodeSize >= 8)
805 RawCode += ( ((int) Raster[ByteOffset + 2]) << 16);
806 RawCode >>= (BitOffset % 8);
807 BitOffset += CodeSize;
808
809 return(RawCode & ReadMask);
810 }
811
812
813 /***************************/
doInterlace(Index)814 static void doInterlace(Index)
815 int Index;
816 {
817 static byte *ptr = NULL;
818 static int oldYC = -1;
819
820 if (Pass == -1) { /* first time through - init stuff */
821 oldYC = -1;
822 Pass = 0;
823 }
824
825 if (oldYC != YC) { ptr = pic8 + YC * Width; oldYC = YC; }
826
827 if (YC<Height)
828 *ptr++ = Index;
829
830 /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
831
832 if (++XC == Width) {
833
834 /* deal with the interlace as described in the GIF
835 * spec. Put the decoded scan line out to the screen if we haven't gone
836 * past the bottom of it
837 */
838
839 XC = 0;
840
841 switch (Pass) {
842 case 0:
843 YC += 8;
844 if (YC >= Height) { Pass++; YC = 4; }
845 break;
846
847 case 1:
848 YC += 8;
849 if (YC >= Height) { Pass++; YC = 2; }
850 break;
851
852 case 2:
853 YC += 4;
854 if (YC >= Height) { Pass++; YC = 1; }
855 break;
856
857 case 3:
858 YC += 2; break;
859
860 default:
861 break;
862 }
863 }
864 }
865
866
867
868 /*****************************/
gifError(pinfo,st)869 static int gifError(pinfo, st)
870 PICINFO *pinfo;
871 const char *st;
872 {
873 gifWarning(st);
874
875 if (RawGIF != NULL) free(RawGIF);
876 if (Raster != NULL) free(Raster);
877
878 if (pinfo->pic) free(pinfo->pic);
879 if (pinfo->comment) free(pinfo->comment);
880
881 if (pic8 && pic8 != pinfo->pic) free(pic8);
882
883 pinfo->pic = (byte *) NULL;
884 pinfo->comment = (char *) NULL;
885
886 return 0;
887 }
888
889
890 /*****************************/
gifWarning(st)891 static void gifWarning(st)
892 const char *st;
893 {
894 SetISTR(ISTR_WARNING,"%s: %s", bname, st);
895 }
896
897
898