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