xref: /PHP-8.0/ext/gd/libgd/gd_gif_in.c (revision 2a9fc310)
1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 #include "gd_errors.h"
7 
8 #include "php.h"
9 
10 /* Used only when debugging GIF compression code */
11 /* #define DEBUGGING_ENVARS */
12 
13 #ifdef DEBUGGING_ENVARS
14 
15 static int verbose_set = 0;
16 static int verbose;
17 #define VERBOSE (verbose_set?verbose:set_verbose())
18 
set_verbose(void)19 static int set_verbose(void)
20 {
21 	verbose = !!getenv("GIF_VERBOSE");
22 	verbose_set = 1;
23 	return(verbose);
24 }
25 
26 #else
27 
28 #define VERBOSE 0
29 
30 #endif
31 
32 
33 #define        MAXCOLORMAPSIZE         256
34 
35 #define        TRUE    1
36 #define        FALSE   0
37 
38 #define CM_RED         0
39 #define CM_GREEN       1
40 #define CM_BLUE                2
41 
42 #define        MAX_LWZ_BITS            12
43 
44 #define INTERLACE              0x40
45 #define LOCALCOLORMAP  0x80
46 #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
47 
48 #define        ReadOK(file,buffer,len) (gdGetBuf(buffer, len, file) > 0)
49 
50 #define LM_to_uint(a,b)                        (((b)<<8)|(a))
51 
52 /* We may eventually want to use this information, but def it out for now */
53 #if 0
54 static struct {
55 	unsigned int    Width;
56 	unsigned int    Height;
57 	unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
58 	unsigned int    BitPixel;
59 	unsigned int    ColorResolution;
60 	unsigned int    Background;
61 	unsigned int    AspectRatio;
62 } GifScreen;
63 #endif
64 
65 #if 0
66 static struct {
67 	int     transparent;
68 	int     delayTime;
69 	int     inputFlag;
70 	int     disposal;
71 } Gif89 = { -1, -1, -1, 0 };
72 #endif
73 
74 #define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2)
75 
76 #define CSD_BUF_SIZE 280
77 
78 typedef struct {
79 	unsigned char    buf[CSD_BUF_SIZE];
80 	int              curbit, lastbit, done, last_byte;
81 } CODE_STATIC_DATA;
82 
83 typedef struct {
84 	int fresh;
85 	int code_size, set_code_size;
86 	int max_code, max_code_size;
87 	int firstcode, oldcode;
88 	int clear_code, end_code;
89 	int table[2][(1<< MAX_LWZ_BITS)];
90 	int stack[STACK_SIZE], *sp;
91 	CODE_STATIC_DATA scd;
92 } LZW_STATIC_DATA;
93 
94 static int ReadColorMap (gdIOCtx *fd, int number, unsigned char (*buffer)[256]);
95 static int DoExtension (gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP);
96 static int GetDataBlock (gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP);
97 static int GetCode (gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP);
98 static int LWZReadByte (gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP);
99 
100 static void ReadImage (gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP); /*1.4//, int ignore); */
101 
gdImageCreateFromGifSource(gdSourcePtr inSource)102 gdImagePtr gdImageCreateFromGifSource(gdSourcePtr inSource) /* {{{ */
103 {
104 	gdIOCtx         *in = gdNewSSCtx(inSource, NULL);
105 	gdImagePtr      im;
106 
107 	im = gdImageCreateFromGifCtx(in);
108 
109 	in->gd_free(in);
110 
111 	return im;
112 }
113 /* }}} */
114 
gdImageCreateFromGif(FILE * fdFile)115 gdImagePtr gdImageCreateFromGif(FILE *fdFile) /* {{{ */
116 {
117 	gdIOCtx		*fd = gdNewFileCtx(fdFile);
118 	gdImagePtr    	im = 0;
119 
120 	im = gdImageCreateFromGifCtx(fd);
121 
122 	fd->gd_free(fd);
123 
124 	return im;
125 }
126 /* }}} */
127 
gdImageCreateFromGifCtx(gdIOCtxPtr fd)128 gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr fd) /* {{{ */
129 {
130 	int BitPixel;
131 #if 0
132 	int ColorResolution;
133 	int Background;
134 	int AspectRatio;
135 #endif
136 	int Transparent = (-1);
137 	unsigned char   buf[16];
138 	unsigned char   c;
139 	unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
140 	unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
141 	int             imw, imh, screen_width, screen_height;
142 	int             useGlobalColormap;
143 	int             bitPixel;
144 	int	       i;
145 	/*1.4//int             imageCount = 0; */
146 
147 	int ZeroDataBlock = FALSE;
148 	int haveGlobalColormap;
149 	gdImagePtr im = 0;
150 
151 	memset(ColorMap, 0, 3 * MAXCOLORMAPSIZE);
152 	memset(localColorMap, 0, 3 * MAXCOLORMAPSIZE);
153 
154 	/*1.4//imageNumber = 1; */
155 	if (! ReadOK(fd,buf,6)) {
156 		return 0;
157 	}
158 	if (strncmp((char *)buf,"GIF",3) != 0) {
159 		return 0;
160 	}
161 
162 	if (memcmp((char *)buf+3, "87a", 3) == 0) {
163 		/* GIF87a */
164 	} else if (memcmp((char *)buf+3, "89a", 3) == 0) {
165 		/* GIF89a */
166 	} else {
167 		return 0;
168 	}
169 
170 	if (! ReadOK(fd,buf,7)) {
171 		return 0;
172 	}
173 
174 	BitPixel        = 2<<(buf[4]&0x07);
175 #if 0
176 	ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
177 	Background      = buf[5];
178 	AspectRatio     = buf[6];
179 #endif
180 	screen_width = imw = LM_to_uint(buf[0],buf[1]);
181 	screen_height = imh = LM_to_uint(buf[2],buf[3]);
182 
183 	haveGlobalColormap = BitSet(buf[4], LOCALCOLORMAP);    /* Global Colormap */
184 	if (haveGlobalColormap) {
185 		if (ReadColorMap(fd, BitPixel, ColorMap)) {
186 			return 0;
187 		}
188 	}
189 
190 	for (;;) {
191 		int top, left;
192 		int width, height;
193 
194 		if (! ReadOK(fd,&c,1)) {
195 			return 0;
196 		}
197 		if (c == ';') {         /* GIF terminator */
198 			goto terminated;
199 		}
200 
201 		if (c == '!') {         /* Extension */
202 			if (! ReadOK(fd,&c,1)) {
203 				return 0;
204 			}
205 			DoExtension(fd, c, &Transparent, &ZeroDataBlock);
206 			continue;
207 		}
208 
209 		if (c != ',') {         /* Not a valid start character */
210 			continue;
211 		}
212 
213 		/*1.4//++imageCount; */
214 
215 		if (! ReadOK(fd,buf,9)) {
216 			return 0;
217 		}
218 
219 		useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
220 
221 		bitPixel = 1<<((buf[8]&0x07)+1);
222 		left = LM_to_uint(buf[0], buf[1]);
223 		top = LM_to_uint(buf[2], buf[3]);
224 		width = LM_to_uint(buf[4], buf[5]);
225 		height = LM_to_uint(buf[6], buf[7]);
226 
227 		if (left + width > screen_width || top + height > screen_height) {
228 			if (VERBOSE) {
229 				printf("Frame is not confined to screen dimension.\n");
230 			}
231 			return 0;
232 		}
233 
234 		if (!(im = gdImageCreate(width, height))) {
235 			return 0;
236 		}
237 		im->interlace = BitSet(buf[8], INTERLACE);
238 		if (!useGlobalColormap) {
239 			if (ReadColorMap(fd, bitPixel, localColorMap)) {
240 				gdImageDestroy(im);
241 				return 0;
242 			}
243 			ReadImage(im, fd, width, height, localColorMap,
244 					BitSet(buf[8], INTERLACE), &ZeroDataBlock);
245 		} else {
246 			if (!haveGlobalColormap) {
247 				gdImageDestroy(im);
248 				return 0;
249 			}
250 			ReadImage(im, fd, width, height,
251 						ColorMap,
252 						BitSet(buf[8], INTERLACE), &ZeroDataBlock);
253 		}
254 		if (Transparent != (-1)) {
255 			gdImageColorTransparent(im, Transparent);
256 		}
257 		goto terminated;
258 	}
259 
260 terminated:
261 	/* Terminator before any image was declared! */
262 	if (!im) {
263 		return 0;
264 	}
265 	/* Check for open colors at the end, so
266 	   we can reduce colorsTotal and ultimately
267 	   BitsPerPixel */
268 	for (i=((im->colorsTotal-1)); (i>=0); i--) {
269 		if (im->open[i]) {
270 			im->colorsTotal--;
271 		} else {
272 			break;
273 		}
274 	}
275 	if (!im->colorsTotal) {
276 		gdImageDestroy(im);
277 		return 0;
278 	}
279 	return im;
280 }
281 /* }}} */
282 
ReadColorMap(gdIOCtx * fd,int number,unsigned char (* buffer)[256])283 static int ReadColorMap(gdIOCtx *fd, int number, unsigned char (*buffer)[256]) /* {{{ */
284 {
285 	int             i;
286 	unsigned char   rgb[3];
287 
288 
289 	for (i = 0; i < number; ++i) {
290 		if (! ReadOK(fd, rgb, sizeof(rgb))) {
291 			return TRUE;
292 		}
293 		buffer[CM_RED][i] = rgb[0] ;
294 		buffer[CM_GREEN][i] = rgb[1] ;
295 		buffer[CM_BLUE][i] = rgb[2] ;
296 	}
297 
298 
299 	return FALSE;
300 }
301 /* }}} */
302 
303 static int
DoExtension(gdIOCtx * fd,int label,int * Transparent,int * ZeroDataBlockP)304 DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
305 {
306 	unsigned char buf[256];
307 
308 	switch (label) {
309 		case 0xf9:              /* Graphic Control Extension */
310 			memset(buf, 0, 4); /* initialize a few bytes in the case the next function fails */
311                (void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP);
312 #if 0
313 			Gif89.disposal    = (buf[0] >> 2) & 0x7;
314 			Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
315 			Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
316 #endif
317 			if ((buf[0] & 0x1) != 0)
318 				*Transparent = buf[3];
319 
320 			while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);
321 			return FALSE;
322 		default:
323 			break;
324 	}
325        while (GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0)
326 		;
327 
328 	return FALSE;
329 }
330 /* }}} */
331 
332 static int
GetDataBlock_(gdIOCtx * fd,unsigned char * buf,int * ZeroDataBlockP)333 GetDataBlock_(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
334 {
335 	unsigned char   count;
336 
337 	if (! ReadOK(fd,&count,1)) {
338 		return -1;
339 	}
340 
341 	*ZeroDataBlockP = count == 0;
342 
343 	if ((count != 0) && (! ReadOK(fd, buf, count))) {
344 		return -1;
345 	}
346 
347 	return count;
348 }
349 /* }}} */
350 
351 static int
GetDataBlock(gdIOCtx * fd,unsigned char * buf,int * ZeroDataBlockP)352 GetDataBlock(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
353 {
354 	int rv;
355 	int i;
356 
357 	rv = GetDataBlock_(fd,buf, ZeroDataBlockP);
358 	if (VERBOSE) {
359 		char *tmp = NULL;
360 		if (rv > 0) {
361 			tmp = safe_emalloc(3 * rv, sizeof(char), 1);
362 			for (i=0;i<rv;i++) {
363 				sprintf(&tmp[3*sizeof(char)*i], " %02x", buf[i]);
364 			}
365 		} else {
366 			tmp = estrdup("");
367 		}
368 		gd_error_ex(GD_NOTICE, "[GetDataBlock returning %d: %s]", rv, tmp);
369 		efree(tmp);
370 	}
371 	return(rv);
372 }
373 /* }}} */
374 
375 static int
GetCode_(gdIOCtx * fd,CODE_STATIC_DATA * scd,int code_size,int flag,int * ZeroDataBlockP)376 GetCode_(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
377 {
378 	int           i, j, ret;
379 	int           count;
380 
381 	if (flag) {
382 		scd->curbit = 0;
383 		scd->lastbit = 0;
384 		scd->last_byte = 2;
385 		scd->done = FALSE;
386 		return 0;
387 	}
388 
389 	if ( (scd->curbit + code_size) >= scd->lastbit) {
390 		if (scd->done) {
391 			if (scd->curbit >= scd->lastbit) {
392 				/* Oh well */
393 			}
394 			return -1;
395 		}
396 		scd->buf[0] = scd->buf[scd->last_byte-2];
397 		scd->buf[1] = scd->buf[scd->last_byte-1];
398 
399                if ((count = GetDataBlock(fd, &scd->buf[2], ZeroDataBlockP)) <= 0)
400 			scd->done = TRUE;
401 
402 		scd->last_byte = 2 + count;
403 		scd->curbit = (scd->curbit - scd->lastbit) + 16;
404 		scd->lastbit = (2+count)*8 ;
405 	}
406 
407 	if ((scd->curbit + code_size - 1) >= (CSD_BUF_SIZE * 8)) {
408 		ret = -1;
409 	} else {
410 		ret = 0;
411 		for (i = scd->curbit, j = 0; j < code_size; ++i, ++j) {
412 			ret |= ((scd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
413 		}
414 	}
415 
416 	scd->curbit += code_size;
417 	return ret;
418 }
419 
420 static int
GetCode(gdIOCtx * fd,CODE_STATIC_DATA * scd,int code_size,int flag,int * ZeroDataBlockP)421 GetCode(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
422 {
423 	int rv;
424 
425  rv = GetCode_(fd, scd, code_size,flag, ZeroDataBlockP);
426  if (VERBOSE) printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
427 	return(rv);
428 }
429 /* }}} */
430 
431 static int
LWZReadByte_(gdIOCtx * fd,LZW_STATIC_DATA * sd,char flag,int input_code_size,int * ZeroDataBlockP)432 LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
433 {
434 	int code, incode, i;
435 
436 	if (flag) {
437 		sd->set_code_size = input_code_size;
438 		sd->code_size = sd->set_code_size+1;
439 		sd->clear_code = 1 << sd->set_code_size ;
440 		sd->end_code = sd->clear_code + 1;
441 		sd->max_code_size = 2*sd->clear_code;
442 		sd->max_code = sd->clear_code+2;
443 
444 		GetCode(fd, &sd->scd, 0, TRUE, ZeroDataBlockP);
445 
446 		sd->fresh = TRUE;
447 
448 		for (i = 0; i < sd->clear_code; ++i) {
449 			sd->table[0][i] = 0;
450 			sd->table[1][i] = i;
451 		}
452 		for (; i < (1<<MAX_LWZ_BITS); ++i)
453 			sd->table[0][i] = sd->table[1][0] = 0;
454 
455 		sd->sp = sd->stack;
456 
457 		return 0;
458 	} else if (sd->fresh) {
459 		sd->fresh = FALSE;
460 		do {
461 			sd->firstcode = sd->oldcode =
462 			GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
463 		} while (sd->firstcode == sd->clear_code);
464 		return sd->firstcode;
465 	}
466 
467 	if (sd->sp > sd->stack)
468 		return *--sd->sp;
469 
470 	while ((code = GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP)) >= 0) {
471 		if (code == sd->clear_code) {
472 			for (i = 0; i < sd->clear_code; ++i) {
473 				sd->table[0][i] = 0;
474 				sd->table[1][i] = i;
475 			}
476 			for (; i < (1<<MAX_LWZ_BITS); ++i)
477 				sd->table[0][i] = sd->table[1][i] = 0;
478 			sd->code_size = sd->set_code_size+1;
479 			sd->max_code_size = 2*sd->clear_code;
480 			sd->max_code = sd->clear_code+2;
481 			sd->sp = sd->stack;
482 			sd->firstcode = sd->oldcode =
483 								GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
484 			return sd->firstcode;
485 		} else if (code == sd->end_code) {
486 			int             count;
487 			unsigned char   buf[260];
488 
489 			if (*ZeroDataBlockP)
490 				return -2;
491 
492 			while ((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0)
493 				;
494 
495 			if (count != 0)
496 				return -2;
497 		}
498 
499 		incode = code;
500 
501 		if (sd->sp == (sd->stack + STACK_SIZE)) {
502 			/* Bad compressed data stream */
503 			return -1;
504 		}
505 
506 		if (code >= sd->max_code) {
507 			*sd->sp++ = sd->firstcode;
508 			code = sd->oldcode;
509 		}
510 
511 		while (code >= sd->clear_code) {
512 			if (sd->sp == (sd->stack + STACK_SIZE)) {
513 				/* Bad compressed data stream */
514 				return -1;
515 			}
516 			*sd->sp++ = sd->table[1][code];
517 			if (code == sd->table[0][code]) {
518 				/* Oh well */
519 			}
520 			code = sd->table[0][code];
521 		}
522 
523 		*sd->sp++ = sd->firstcode = sd->table[1][code];
524 
525 		if ((code = sd->max_code) <(1<<MAX_LWZ_BITS)) {
526 			sd->table[0][code] = sd->oldcode;
527 			sd->table[1][code] = sd->firstcode;
528 			++sd->max_code;
529 			if ((sd->max_code >= sd->max_code_size) &&
530 					(sd->max_code_size < (1<<MAX_LWZ_BITS))) {
531 				sd->max_code_size *= 2;
532 				++sd->code_size;
533 			}
534 		}
535 
536 		sd->oldcode = incode;
537 
538 		if (sd->sp > sd->stack)
539 			return *--sd->sp;
540 	}
541 	return code;
542 }
543 /* }}} */
544 
545 static int
LWZReadByte(gdIOCtx * fd,LZW_STATIC_DATA * sd,char flag,int input_code_size,int * ZeroDataBlockP)546 LWZReadByte(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
547 {
548 	int rv;
549 
550  rv = LWZReadByte_(fd, sd, flag, input_code_size, ZeroDataBlockP);
551  if (VERBOSE) printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
552 	return(rv);
553 }
554 /* }}} */
555 
556 static void
ReadImage(gdImagePtr im,gdIOCtx * fd,int len,int height,unsigned char (* cmap)[256],int interlace,int * ZeroDataBlockP)557 ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP) /*1.4//, int ignore) */
558 {
559 	unsigned char   c;
560 	int             v;
561 	int             xpos = 0, ypos = 0, pass = 0;
562 	int i;
563 	LZW_STATIC_DATA sd;
564 
565 
566 	/*
567 	 **  Initialize the Compression routines
568 	 */
569 	if (! ReadOK(fd,&c,1)) {
570 		return;
571 	}
572 
573 	if (c > MAX_LWZ_BITS) {
574 		return;
575 	}
576 
577 	/* Stash the color map into the image */
578 	for (i=0; (i<gdMaxColors); i++) {
579 		im->red[i] = cmap[CM_RED][i];
580 		im->green[i] = cmap[CM_GREEN][i];
581 		im->blue[i] = cmap[CM_BLUE][i];
582 		im->open[i] = 1;
583 	}
584 	/* Many (perhaps most) of these colors will remain marked open. */
585 	im->colorsTotal = gdMaxColors;
586 	if (LWZReadByte(fd, &sd, TRUE, c, ZeroDataBlockP) < 0) {
587 		return;
588 	}
589 
590 	/*
591 	 **  If this is an "uninteresting picture" ignore it.
592 	 **  REMOVED For 1.4
593 	 */
594 	/*if (ignore) { */
595 	/*        while (LWZReadByte(fd, &sd, FALSE, c) >= 0) */
596 	/*                ; */
597 	/*        return; */
598 	/*} */
599 
600 	while ((v = LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP)) >= 0) {
601 		if (v >= gdMaxColors) {
602 			v = 0;
603 		}
604 		/* This how we recognize which colors are actually used. */
605 		if (im->open[v]) {
606 			im->open[v] = 0;
607 		}
608 		gdImageSetPixel(im, xpos, ypos, v);
609 		++xpos;
610 		if (xpos == len) {
611 			xpos = 0;
612 			if (interlace) {
613 				switch (pass) {
614 					case 0:
615 					case 1:
616 						ypos += 8; break;
617 					case 2:
618 						ypos += 4; break;
619 					case 3:
620 						ypos += 2; break;
621 				}
622 
623 				if (ypos >= height) {
624 					++pass;
625 					switch (pass) {
626 						case 1:
627 							ypos = 4; break;
628 						case 2:
629 							ypos = 2; break;
630 						case 3:
631 							ypos = 1; break;
632 						default:
633 							goto fini;
634 					}
635 				}
636 			} else {
637 				++ypos;
638 			}
639 		}
640 		if (ypos >= height)
641 			break;
642 	}
643 
644 fini:
645 	if (LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP) >=0) {
646 		/* Ignore extra */
647 	}
648 }
649 /* }}} */
650