1 
2 /* gif.c Decodes gif images. */
3 
4 #include <stdio.h>
5 #include <stdlib.h>
6 
7 #include "modules.h"
8 #include "gif.h"
9 
10 #define M_TRAILER     0x3B
11 #define M_IMAGE       0x2C
12 #define M_EXTENSION   0x21
13 
14 static int gif_width,gif_height;
15 static FILE *giffile;
16 static long int gif_filesize;
17 static const char *gifmarker="GIF";
18 static int gif_gctdef=0;
19 static int gif_resolution=0;
20 static int gif_colors=0;
21 static int gif_background=0;
22 static int gif_aspectratio=0;
23 static int *gif_pal;
24 static int gif_palmask;
25 static unsigned char *gif_data,*data;
26 static int gif_interlaced=0;
27 static int bitpos,maxbits;
28 static unsigned char bitbuf[256];
29 static int initcodesize,codesize,codemask,gif_ipixel,gif_iindex,
30 	   gif_ipassnr,gif_ipassinc;
31 
32 /* prototypes */
33 void readColormap(int);
34 
35 
gif_readword(void)36 static int gif_readword(void)
37 {
38 	return (fgetc(giffile)|(fgetc(giffile)<<8))&0xFFFF;
39 }
40 
readColormap(int colors)41 void readColormap(int colors)
42 {
43 	int i;
44 
45 	for (i=0;i<colors;i++)
46 		gif_pal[i]=gif_readword()|(fgetc(giffile)<<16);
47 }
48 
readCode(void)49 static int readCode(void)
50 {
51 	int bits,size;
52 
53 	bits=size=0;
54 
55 	while (size<codesize) {
56 		if (bitpos>=maxbits) {
57 			if ((maxbits=fgetc(giffile))==EOF) return -1;
58 			maxbits<<=3;
59 			fread(bitbuf,1,(size_t)(maxbits>>3),giffile);
60 			bitpos=0;
61 		}
62 		bits=bits|(((bitbuf[bitpos>>3]>>(bitpos&7))&1)<<size);
63 		bitpos++;size++;
64 	}
65 
66 	return bits & codemask;
67 }
68 
saveColor(int nr)69 static void saveColor(int nr)
70 {
71 	if (data-gif_data>=gif_width*gif_height) {
72 		/* printf("Error: data overflow.\n"); */
73 		return;
74 	}
75 	*data++=nr;
76 
77 	if (gif_interlaced) {
78 		if ((++gif_ipixel)>=gif_width) {
79 			gif_ipixel=0;
80 			gif_iindex+=gif_ipassinc;
81 			if (gif_iindex>=gif_height) {
82 				switch (++gif_ipassnr) {
83 				case 1:
84 					gif_ipassinc=8;
85 					gif_iindex=4;
86 					break;
87 				case 2:
88 					gif_ipassinc=4;
89 					gif_iindex=2;
90 					break;
91 				case 3:
92 					gif_ipassinc=2;
93 					gif_iindex=1;
94 					break;
95 				}
96 			}
97 			data=gif_data+gif_iindex*gif_width;
98 		}
99 	}
100 }
101 
readImage(void)102 static int readImage(void)
103 {
104 	int leftoffs,topoffs,info,CC,EOFC,savecode,
105 	    code,lastcode=0,lastchar=0,curcode,freecode,initfreecode,outcodenr;
106 	int prefix[4096];
107 	unsigned char suffix[4096],output[4096];
108 
109 	leftoffs=gif_readword();topoffs=gif_readword();
110 	gif_width=gif_readword();gif_height=gif_readword();
111 
112 	gif_data=(unsigned char *)malloc((size_t)(gif_width*gif_height));
113 
114 	if (!gif_data) {
115 		printf("Out of memory.\n");
116 		fclose(giffile);giffile=NULL;
117 		return 1;
118 	}
119 
120 	info=fgetc(giffile);
121 	gif_interlaced=info&0x40;
122 	if (info&0x80) readColormap((int)1 <<((info&7)+1));
123 
124 	/*  if (leftoffs||topoffs) {
125 	    printf("Warning: image offset (%i, %i)\n",leftoffs,topoffs);
126 	    return 1;
127 	    }*/
128 
129 	data=gif_data;
130 	initcodesize=fgetc(giffile);
131 	bitpos=maxbits=0;
132 	CC=1<<initcodesize;
133 	EOFC=CC+1;
134 	freecode=initfreecode=CC+2;
135 	codesize=++initcodesize;
136 	codemask=(1<<codesize)-1;
137 	gif_iindex=gif_ipassnr=0;
138 	gif_ipassinc=8;
139 	gif_ipixel=0;
140 
141 	if ((code=readCode())>=0)
142 		while (code!=EOFC) {
143 			if (code==CC) {
144 				codesize=initcodesize;
145 				codemask=(1<<codesize)-1;
146 				freecode=initfreecode;
147 				lastcode=lastchar=code=readCode();
148 				if (code<0) break;
149 				saveColor(code);
150 			} else {
151 				outcodenr=0;savecode=code;
152 				if (code>=freecode) {
153 					if (code>freecode) break;
154 					output[(outcodenr++) & 0xFFF]=lastchar;
155 					code=lastcode;
156 				}
157 				curcode=code;
158 
159 				while (curcode>gif_palmask) {
160 					if (outcodenr>4095) break;
161 					output[(outcodenr++)&0xFFF]=suffix[curcode];
162 					curcode=prefix[curcode];
163 				}
164 
165 				output[(outcodenr++)&0xFFF]=lastchar=curcode;
166 
167 				while (outcodenr>0)
168 					saveColor(output[--outcodenr]);
169 
170 				prefix[freecode]=lastcode;
171 				suffix[freecode++]=lastchar;
172 				lastcode=savecode;
173 
174 				if (freecode>codemask) {
175 					if (codesize<12) {
176 						codesize++;
177 						codemask=(codemask<<1)|1;
178 					}
179 				}
180 			}
181 			if ((code=readCode())<0) break;
182 		}
183 	return 0;
184 }
185 
186 /* output size will be ignored */
GIF_OpenFile(const char * filename,const char * imgdir,unsigned int owidth,unsigned int oheight)187 int GIF_OpenFile(const char *filename,const char *imgdir,
188     unsigned int owidth, unsigned int oheight)
189 {
190 	int i,marker;
191 
192 	UNUSED(imgdir); UNUSED(owidth); UNUSED(oheight);
193 
194 	gif_data=NULL;
195 	gif_pal=NULL;
196 	gif_width=gif_height=0;
197 
198 	giffile=NULL;
199 	giffile=fopen(filename,"rb");
200 	if (!giffile) return 0;
201 
202 	fseek(giffile,0,SEEK_END);
203 	gif_filesize=ftell(giffile);
204 	rewind(giffile);
205 
206 	if (gif_filesize<13) {
207 		fclose(giffile);giffile=NULL;
208 		return 0;
209 	}
210 
211 	for (i=0;i<3;i++)
212 		if (fgetc(giffile)!=gifmarker[i]) {
213 			fclose(giffile);giffile=NULL;
214 			return 0;
215 		}
216 
217 	/* skip version info for now */
218 	for (i=0;i<3;i++)
219 		fgetc(giffile);
220 
221 	gif_width=gif_readword();
222 	gif_height=gif_readword();
223 
224 	i=fgetc(giffile);
225 	gif_gctdef=i&0x80;
226 	gif_resolution=((i>>4)&7)+1;
227 	gif_colors=(int)1 << ((i&7)+1);
228 	gif_palmask=gif_colors-1;
229 
230 	gif_background=fgetc(giffile);
231 	gif_aspectratio=fgetc(giffile);
232 
233 	if (gif_aspectratio) {
234 		printf("Hmm: ASPECT RATIO given ! What to do ?\n");
235 		fclose(giffile);giffile=NULL;
236 		return 0;
237 	}
238 
239 	gif_pal=malloc(256*sizeof(int));
240 	if (gif_gctdef) readColormap(gif_colors);
241 
242 	do {
243 		if ((marker=fgetc(giffile))==EOF) break;
244 
245 		switch (marker) {
246 		case M_IMAGE:
247 			readImage();fgetc(giffile);
248 			break;
249 		case M_EXTENSION:
250 			fgetc(giffile);
251 			i=fgetc(giffile);
252 			while (i) {
253 				while (i--) fgetc(giffile);
254 				i=fgetc(giffile);
255 			}
256 			break;
257 		case M_TRAILER:
258 			break;
259 		default:
260 			i=fgetc(giffile);
261 			while (i) {
262 				while (i--) fgetc(giffile);
263 				i=fgetc(giffile);
264 			}
265 			break;
266 		}
267 	} while (marker!=M_TRAILER);
268 
269 	fclose(giffile);giffile=NULL;
270 	return 1;
271 }
272 
GIF_CloseFile(void)273 void GIF_CloseFile(void)
274 {
275 	if (gif_pal!=NULL) free(gif_pal);
276 	if (gif_data!=NULL) free(gif_data);
277 
278 	if (giffile!=NULL) fclose(giffile);
279 	giffile=NULL;
280 }
281 
GIF_GetPixel(int x,int y,int col)282 unsigned int GIF_GetPixel(int x,int y,int col)
283 {
284 	int color;
285 
286 	if ((x>=gif_width)||(y>=gif_height))
287 		return 0x000000;
288 
289 	color=gif_pal[gif_data[y*gif_width+x]];
290 
291 	return col ? (color&0xFF00)|((color>>16)&0xFF)|((color&0xFF)<<16) :
292 	    (((color&0xFF)+((color>>8)&0xFF)+((color>>16)&0xFF))/3)*0x010101;
293 }
294 
GIF_GetWidth(void)295 int GIF_GetWidth(void)
296 {
297 	return gif_width;
298 }
299 
GIF_GetHeight(void)300 int GIF_GetHeight(void)
301 {
302 	return gif_height;
303 }
304