1 /*
2  * OpenBOR - http://www.LavaLit.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2011 OpenBOR Team
7  */
8 
9 // Animated GIF player.
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include "packfile.h"
14 #include "borendian.h"
15 #include "types.h"
16 #include "screen.h"
17 #include "anigif.h"
18 
19 // Animated GIF player.
20 
21 
readbyte(int handle)22 static unsigned char readbyte(int handle){
23 	unsigned char c = 0;
24 	readpackfile(handle, &c, 1);
25 	return c;
26 }
27 
passgifblock(anigif_info * info)28 static void passgifblock(anigif_info* info){
29 	int len;
30 
31 	// Skip all contained blocks
32 	while((len=readbyte(info->handle))!=0) seekpackfile(info->handle, len, SEEK_CUR);
33 }
34 
35 
36 
handle_gfx_control(anigif_info * info)37 static void handle_gfx_control(anigif_info* info){
38 	int len;
39 	int skip;
40 	unsigned char buf[4];
41 
42 
43 	// Handle all contained blocks
44 	while((len=readbyte(info->handle))!=0){
45 		skip = len - 4;
46 		if(len>4) len = 4;
47 		readpackfile(info->handle, buf, len);
48 		if(skip>0) seekpackfile(info->handle, skip, SEEK_CUR);
49 
50 		if(buf[0]&1) info->transparent = buf[3];
51 		info->lastdelay = (buf[2]<<8) | buf[1];
52 
53 		// disposal = (buf[0]>>2) & 7;
54 		// inputflag = (buf[0]>>1) & 1;
55 	}
56 }
57 
58 
59 
gifextension(anigif_info * info)60 static void gifextension(anigif_info* info){
61 	int function;
62 
63 	// Get extension function code
64 	function = readbyte(info->handle);
65 
66 	// Note: function may be repeated multiple times (size, data, size, data)
67 	switch(function){
68 		case 0xF9:
69 			// Graphic control
70 			handle_gfx_control(info);
71 			return;
72 		default:
73 			// 0x01 = text
74 			// 0xFF = app. extension
75 			// 0xFE = comment
76 			passgifblock(info);
77 			return;
78 	}
79 }
80 
81 
82 
83 /*
84 int readnonzero(int handle){
85 	char b = 0;
86 	while(b==0){
87 		if(readpackfile(handle, &b, 1) < 1) return 0;
88 	}
89 	return b;
90 }
91 */
92 
93 
94 
95 
decodegifblock(anigif_info * info,s_screen * buf,int width,int height,gifblockstruct * gb)96 static int decodegifblock(anigif_info* info, s_screen* buf, int width, int height, gifblockstruct *gb){
97 
98 	unsigned char bits;
99 	short bits2;
100 	short codesize;
101 	short codesize2;
102 	short nextcode;
103 	short thiscode;
104 	short oldtoken;
105 	short currentcode;
106 	short oldcode;
107 	short bitsleft;
108 	short blocksize;
109 	int line = 0, lineb;
110 	int byte = gb->left;
111 	int pass = 0;
112 
113 	unsigned char *p;
114 	unsigned char *u;
115 
116 	unsigned char *q;
117 	unsigned char b[255];
118 
119 	static unsigned char firstcodestack[4096];
120 	static unsigned char lastcodestack[4096];
121 	static short codestack[4096];
122 
123 	static short wordmasktable[] = {0x0000, 0x0001, 0x0003, 0x0007,
124 					0x000f, 0x001f, 0x003f, 0x007f,
125 					0x00ff, 0x01ff, 0x03ff, 0x07ff,
126 					0x0fff, 0x1fff, 0x3fff, 0x7fff };
127 
128 	static short inctable[] = { 8, 8, 4, 2, 0 };
129 	static short startable[] = { 0, 4, 2, 1, 0 };
130 
131 
132 	// get the initial LZW code bits
133 	bits = readbyte(info->handle);
134 	if(bits<2 || bits>8) return 0;
135 
136 	p = q = b;
137 	bitsleft = 8;
138 
139 	bits2 = 1 << bits;
140 	nextcode = bits2 + 2;
141 	codesize2 = 1 << (codesize = bits + 1);
142 	oldcode = oldtoken = NO_CODE;
143 
144 	lineb = gb->top * width;
145 
146 	// loop until something breaks
147 	for(;;){
148 		if(bitsleft == 8){
149 			if(++p >= q && (((blocksize = readbyte(info->handle)) < 1) ||
150 				(q=(p=b) + readpackfile(info->handle, b, blocksize)) < (b+blocksize))){
151 				return 1;	// Done
152 			}
153 			bitsleft = 0;
154 		}
155 		thiscode = *p;
156 		if((currentcode=(codesize+bitsleft)) <= 8){
157 			*p >>= codesize;
158 			bitsleft = currentcode;
159 		}
160 		else{
161 			if(++p >= q && (((blocksize = readbyte(info->handle)) < 1) ||
162 				(q=(p=b)+readpackfile(info->handle, b, blocksize)) < (b+blocksize))){
163 				return 1;	// Done
164 			}
165 
166 			thiscode |= *p << (8 - bitsleft);
167 			if(currentcode<=16) *p >>= (bitsleft = currentcode - 8);
168 			else{
169 				if(++p >= q && (((blocksize = readbyte(info->handle)) < 1) ||
170 					(q=(p=b) + readpackfile(info->handle, b, blocksize)) < (b+blocksize))){
171 					return 1;	// Done
172 				}
173 
174 				thiscode |= *p << (16 - bitsleft);
175 				*p >>= (bitsleft = currentcode - 16);
176 			}
177 		}
178 		thiscode &= wordmasktable[codesize];
179 		currentcode = thiscode;
180 
181 		if(thiscode==(bits2+1)) break;
182 		if(thiscode>nextcode){
183 			return 0;			// Bad code
184 		}
185 
186 		if(thiscode==bits2){
187 			nextcode = bits2 + 2;
188 			codesize2 = 1 << (codesize = (bits+1));
189 			oldtoken = oldcode = NO_CODE;
190 			continue;
191 		}
192 
193 		u = firstcodestack;
194 
195 		if(thiscode==nextcode){
196 			if(oldcode==NO_CODE){
197 				return 0;		// Bad code
198 			}
199 			*u++ = oldtoken;
200 			thiscode = oldcode;
201 		}
202 
203 		while(thiscode>=bits2){
204 			*u++ = lastcodestack [thiscode];
205 			thiscode = codestack[thiscode];
206 		}
207 
208 		oldtoken = thiscode;
209 		do{
210 			if(byte<width && byte>=0 && gb->top+line>=0 && line<(height - gb->top) && thiscode!=info->transparent)
211 			{
212 				switch(buf->pixelformat){
213 				case PIXEL_8:
214 					((unsigned char*)buf->data)[lineb + byte] = thiscode;
215 					break;
216 				case PIXEL_16:
217 					((unsigned short*)buf->data)[lineb + byte] = info->local_pal?((unsigned short*)info->local_pal)[thiscode&0xff]:((unsigned short*)info->global_pal)[thiscode&0xff];
218 					break;
219 				case PIXEL_32:
220 					((unsigned*)buf->data)[lineb + byte] = info->local_pal?((unsigned*)info->local_pal)[thiscode&0xff]:((unsigned*)info->global_pal)[thiscode&0xff];
221 					//printf("%08x, %02x, %ld\n", ((unsigned*)buf->data)[lineb + byte], thiscode&0xff, info->handle);
222 					break;
223 				}
224 			}
225 			byte++;
226 			if(byte >= gb->left + gb->width){
227 				byte = gb->left;
228 				// check for interlaced image
229 				if(gb->flags&0x40){
230 					line += inctable[pass];
231 					if(line >= gb->height) line = startable[++pass];
232 				}
233 				else ++line;
234 				lineb = width*(gb->top+line);
235 			}
236 			if (u<=firstcodestack) break;
237 			thiscode = *--u;
238 		}while(1);
239 
240 		if(nextcode<4096 && oldcode!=NO_CODE){
241 			codestack[nextcode] = oldcode;
242 			lastcodestack[nextcode] = oldtoken;
243 			if(++nextcode>=codesize2 && codesize<12) codesize2 = 1<<++codesize;
244 		}
245 		oldcode = currentcode;
246 	}
247 
248 	return 1;
249 }
250 
251 
252 
253 
254 
255 
256 
257 
anigif_close(anigif_info * info)258 void anigif_close(anigif_info* info){
259 	closepackfile(info->handle);
260 	info->handle = -1;
261 }
262 
263 
264 
265 // Returns true on success
anigif_open(char * filename,char * packfilename,unsigned char * pal,anigif_info * info)266 int anigif_open(char *filename, char *packfilename, unsigned char *pal, anigif_info* info){
267 	unsigned char tpal[1024];
268 	int i, j;
269 	int noblackenbg = info->noblackenbg;
270 
271 	memset(info, 0, sizeof(anigif_info));
272 
273 	info->handle = -1;
274 	info->transparent = -1;
275 	info->noblackenbg = noblackenbg;
276 
277 #if PSP || PS2 || DC
278 	if((info->handle=openreadaheadpackfile(filename,packfilename,1*1024*1024, 131072))==-1) return 0;
279 #else
280 	if((info->handle=openpackfile(filename,packfilename))==-1) return 0;
281 #endif
282 
283 #if PSP || PS2 || DC
284 	if(readpackfile(info->handle,&info->gif_header,sizeof_gifheaderstruct)!=sizeof_gifheaderstruct){
285 #else
286 	if(readpackfile(info->handle,&info->gif_header,sizeof(gifheaderstruct))!=sizeof(gifheaderstruct)){
287 #endif
288 		anigif_close(info);
289 		return 0;
290 	}
291 
292 	if(info->gif_header.magic[0]!='G' || info->gif_header.magic[1]!='I' || info->gif_header.magic[2]!='F'){
293 		// Not a GIF file!
294 		anigif_close(info);
295 		return 0;
296 	}
297 
298 	//info->current_res[0] = SwapLSB16(info->gif_header.screenwidth);
299 	//info->current_res[1] = SwapLSB16(info->gif_header.screenheight);
300 
301 	if(info->gif_header.flags&0x80){
302 		info->bitdepth = (info->gif_header.flags&7)+1;
303 		info->numcolours = 1<<info->bitdepth ;
304 	}else{
305 		info->bitdepth = 8;
306 		info->numcolours = 0;
307 	}
308 	info->lastdelay = 1;
309 	//printf("numcolours:%d\n", info->numcolours);
310 
311 	// Get global palette, if present and if wanted
312 	if(info->gif_header.flags&0x80){
313 		info->global_pal = pal;
314 		if(pal){
315 			if(readpackfile(info->handle, tpal, info->numcolours*3) != info->numcolours*3){
316 
317 				anigif_close(info);
318 				return 0;
319 			}
320 			//*tpal &= 0xFF000000;
321 			if(!noblackenbg) tpal[0] = tpal[1] = tpal[2] = 0;
322 			switch(PAL_BYTES)
323 			{
324 			case 768:
325 				memcpy(pal, tpal, 768);
326 				break;
327 			case 1024:
328 				for(i=0, j=0; i<1024; i+=4, j+=3)
329 				{
330 					*(unsigned*)(pal+i) = colour32(tpal[j], tpal[j+1], tpal[j+2]);
331 				}
332 				break;
333 			case 512:
334 				for(i=0, j=0; i<512; i+=2, j+=3)
335 				{
336 					*(unsigned short*)(pal+i) = colour16(tpal[j], tpal[j+1], tpal[j+2]);
337 				}
338 				break;
339 			}
340 		}
341 		else seekpackfile(info->handle, info->numcolours*3, SEEK_CUR);
342 	}
343 
344 	return 1;
345 }
346 
347 
348 
349 
350 // Returns type of action to take (frame, retry, end)
351 int anigif_decode(s_screen * screen, int *delay, int x, int y, unsigned char* pal, anigif_info* info){
352 
353 	gifblockstruct iblock;
354 	unsigned char tpal[1024];
355 	unsigned char c;
356 	int i, j, numcolours;
357 
358 
359 	if(info->handle<0) return ANIGIF_DECODE_END;
360 	if(screen==NULL){
361 		anigif_close(info);
362 		return ANIGIF_DECODE_END;
363 	}
364 
365 	if(readpackfile(info->handle,&c,1)!=1){
366 		anigif_close(info);
367 		return ANIGIF_DECODE_END;
368 	}
369 
370 
371 	switch(c){
372 		case ',':
373 			// An image block
374 #if PSP || PS2 || DC
375 			if(readpackfile(info->handle, &iblock, sizeof_iblock)!=sizeof_iblock){
376 #else
377 			if(readpackfile(info->handle, &iblock, sizeof(iblock))!=sizeof(iblock)){
378 #endif
379 				anigif_close(info);
380 				return ANIGIF_DECODE_END;
381 			}
382 
383 			if(iblock.flags&0x80){
384 				info->local_pal = pal;
385 				numcolours = 1<<((iblock.flags&7)+1);
386 				if(pal){
387 					if(readpackfile(info->handle, tpal, numcolours*3) != numcolours*3){
388 						anigif_close(info);
389 						return ANIGIF_DECODE_END;
390 					}
391 					if(!info->noblackenbg) tpal[0] = tpal[1] = tpal[2] = 0;
392 					switch(PAL_BYTES)
393 					{
394 					case 768:
395 						memcpy(pal, tpal, 768);
396 						break;
397 					case 1024:
398 						for(i=0, j=0; i<1024; i+=4, j+=3)
399 						{
400 							*(unsigned*)(pal+i) = colour32(tpal[j], tpal[j+1], tpal[j+2]);
401 						}
402 						break;
403 					case 512:
404 						for(i=0, j=0; i<512; i+=2, j+=3)
405 						{
406 							*(unsigned short*)(pal+i) = colour16(tpal[j], tpal[j+1], tpal[j+2]);
407 							//printf("%d*", *(unsigned short*)(pal+i));
408 						}
409 						break;
410 					}
411 					//printf("iblock:%d,%d,%d,%d\n",  SwapLSB16(iblock.left), SwapLSB16(iblock.top), SwapLSB16(iblock.width), SwapLSB16(iblock.height));
412 				}
413 				else seekpackfile(info->handle, numcolours*3, SEEK_CUR);
414 			}
415 
416 			iblock.left = SwapLSB16(iblock.left);
417 			iblock.top = SwapLSB16(iblock.top);
418 			iblock.width = SwapLSB16(iblock.width);
419 			iblock.height = SwapLSB16(iblock.height);
420 			iblock.left += x;
421 			iblock.top += y;
422 
423 			decodegifblock(info, screen, screen->width, screen->height, &iblock);
424 /*
425 			if(!decodegifblock(handle, screen->data, screen->width, screen->height, &iblock)){
426 				anigif_close();
427 				return ANIGIF_DECODE_END;
428 			}
429 */
430 
431 			if(delay) *delay = info->lastdelay;
432 			// lastdelay = 0;
433 			if(iblock.left<0) return ANIGIF_DECODE_RETRY;
434 
435 			return ANIGIF_DECODE_FRAME|((iblock.flags&0x80)?ANIGIF_DECODE_PAL:0);
436 
437 		case '!':
438 			// Handle GIF extension
439 			gifextension(info);
440 			// if(delay) *delay = lastdelay;
441 			// lastdelay = 0;
442 			return ANIGIF_DECODE_RETRY;
443 
444 //		case 0:
445 		default:
446 			// Isn't this an EOF?
447 			return ANIGIF_DECODE_RETRY;
448 //			anigif_close();
449 //			return ANIGIF_DECODE_END;
450 	}
451 
452 	anigif_close(info);
453 	return ANIGIF_DECODE_END;
454 }
455 
456 
457 
458 
459 
460 
461 
462 
463