1 /******************************************************************************
2 *   "Gif-Lib" - Yet another gif library.				      *
3 *									      *
4 * Written by:  Gershon Elber			IBM PC Ver 1.1,	Aug. 1990     *
5 *******************************************************************************
6 * The kernel of the GIF Decoding process can be found here.		      *
7 *******************************************************************************
8 * History:								      *
9 * 16 Jun 89 - Version 1.0 by Gershon Elber.				      *
10 *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
11 ******************************************************************************/
12 
13 #   include	<stdio.h>
14 #   include	<stdlib.h>
15 #   include	<string.h>
16 #   include	"bm_gif_lib.h"
17 
18 #   include	<sioBlocked.h>
19 #   include	<sioLzw.h>
20 #   include	<sioEndian.h>
21 #   include	<appDebugon.h>
22 
23 /************************************************************************/
24 /*									*/
25 /*  Read a palette from the input file.					*/
26 /*									*/
27 /************************************************************************/
28 
bmGifInitGifColorMap(GifColorMap * gcm)29 void bmGifInitGifColorMap(	GifColorMap *	gcm )
30     {
31     int		i;
32     RGB8Color *	rgb8;
33 
34     gcm->gcmColorCount= 0;
35     gcm->gcmBitsPerPixel= 0;
36 
37     rgb8= gcm->gcmColors;
38     for ( i = 0; i < 256; rgb8++, i++ )
39 	{
40 	rgb8->rgb8Red= 255;
41 	rgb8->rgb8Green= 255;
42 	rgb8->rgb8Blue= 255;
43 	rgb8->rgb8Alpha= 255;
44 	}
45 
46     return;
47     }
48 
bmGifReadColorMap(GifFileType * gft,GifColorMap * gcm,int bitsPerPixel)49 static int bmGifReadColorMap(	GifFileType *		gft,
50 				GifColorMap *		gcm,
51 				int			bitsPerPixel )
52     {
53     RGB8Color *		rgb8;
54     int			i;
55 
56     bmGifInitGifColorMap( gcm );
57 
58     gcm->gcmBitsPerPixel= bitsPerPixel;
59     gcm->gcmColorCount= 1 << bitsPerPixel;
60 
61     rgb8= gcm->gcmColors;
62     for ( i = 0; i < gcm->gcmColorCount; rgb8++, i++ )
63 	{
64 	rgb8->rgb8Red= sioInGetByte( gft->gftSis );
65 	rgb8->rgb8Green= sioInGetByte( gft->gftSis );
66 	rgb8->rgb8Blue= sioInGetByte( gft->gftSis );
67 	}
68 
69     return 0;
70     }
71 
72 /************************************************************************/
73 /*									*/
74 /*  Read the screen descriptor from the input file.			*/
75 /*  This is the first information that is read from the file by the	*/
76 /*  open routine.							*/
77 /*									*/
78 /*  1)  Opened for reading?						*/
79 /*  2)  Read screen size.						*/
80 /*  3)  Read the description of the global color map.			*/
81 /*  4)  And interpret it.						*/
82 /*  5)  Read global palette (if any).					*/
83 /*									*/
84 /************************************************************************/
85 
bmGifReadScreenDescriptor(GifFileType * gft)86 static int bmGifReadScreenDescriptor(	GifFileType *	gft )
87 {
88     GifScreenDescriptor *	gsd= &(gft->gftScreenDescriptor);
89 
90     int				bitsPerPixel;
91 
92     /*  1  */
93     if  ( ! gft->gftSis )
94 	{
95 	XDEB(gft->gftSis);
96 	_GifError= D_GIF_ERR_NOT_READABLE;
97 	return GIF_ERROR;
98 	}
99 
100     bmGifInitGifColorMap( &(gsd->gsdScreenColorMap) );
101 
102     /*  2  */
103     gsd->gsdScreenWide= sioEndianGetLeInt16( gft->gftSis );
104     gsd->gsdScreenHigh= sioEndianGetLeInt16( gft->gftSis );
105 
106     /*  3  */
107     gsd->gsdPackedFields= sioInGetByte( gft->gftSis );
108     gsd->gsdScreenBackgroundColor= sioInGetByte( gft->gftSis );
109     gsd->gsdScreenAspectRatio= sioInGetByte( gft->gftSis );
110 
111     /*  4  */
112     gsd->gsdScreenBitsPerPixel = (((gsd->gsdPackedFields & 0x70) + 1) >> 4) + 1;
113     bitsPerPixel= ( gsd->gsdPackedFields & 0x07 ) + 1;
114 
115     /*  5  */
116     if  ( gsd->gsdPackedFields & 0x80 )
117 	{
118 	if  ( bmGifReadColorMap( gft,
119 			    &(gsd->gsdScreenColorMap), bitsPerPixel ) )
120 	    { LDEB(bitsPerPixel); return GIF_ERROR;	}
121 	}
122 
123     return GIF_OK;
124 }
125 
126 /************************************************************************/
127 /*									*/
128 /*  Setup the LZ decompression for this image				*/
129 /*									*/
130 /*  3)  Open the blocked input stream. (Push it on the unstructured	*/
131 /*	one.)								*/
132 /*  4)  Open the LZW stream (Push it on the blocked one.)		*/
133 /*									*/
134 /************************************************************************/
135 
DGifSetupDecompress(GifFileType * gft)136 static int DGifSetupDecompress(	GifFileType *	gft )
137 {
138     int				codeSize;
139 
140     codeSize= sioInGetByte( gft->gftSis );
141     if  ( codeSize == EOF )
142 	{ LDEB(codeSize); return GIF_ERROR;	}
143 
144     /*  3  */
145     if  ( gft->gftSisBlocked )
146 	{ XDEB(gft->gftSisBlocked);	}
147 
148     gft->gftSisBlocked= sioInBlockedOpen( gft->gftSis );
149     if  ( ! gft->gftSisBlocked )
150 	{ XDEB(gft->gftSisBlocked); return GIF_ERROR;	}
151 
152     /*  4  */
153     if  ( gft->gftSisLzw )
154 	{ XDEB(gft->gftSisLzw);	}
155 
156     gft->gftSisLzw= sioInLzwGifOpen( gft->gftSisBlocked, codeSize );
157     if  ( ! gft->gftSisLzw )
158 	{ XDEB(gft->gftSisLzw); return GIF_ERROR;	}
159 
160     return GIF_OK;
161 }
162 
bmGifCleanupDecompress(GifFileType * gft)163 static void bmGifCleanupDecompress(	GifFileType *	gft )
164     {
165     if  ( gft->gftSisLzw )
166 	{
167 	if  ( sioInClose( gft->gftSisLzw ) )
168 	    { XDEB(gft->gftSisLzw);	}
169 
170 	gft->gftSisLzw= (SimpleInputStream *)0;
171 	}
172 
173     if  ( gft->gftSisBlocked )
174 	{
175 	if  ( sioInClose( gft->gftSisBlocked ) )
176 	    { XDEB(gft->gftSisBlocked);	}
177 
178 	gft->gftSisBlocked= (SimpleInputStream *)0;
179 	}
180 
181     return;
182     }
183 
184 /******************************************************************************
185 *   Update a new gif file, given its file handle.                             *
186 *   Returns GifFileType pointer dynamically allocated which serves as the gif *
187 *   info record. _GifError is cleared if succesfull.                          *
188 ******************************************************************************/
189 
DGifOpenFileHandle(SimpleInputStream * sis)190 GifFileType *DGifOpenFileHandle(	SimpleInputStream *	sis )
191 {
192     GifFileType *		gft;
193 
194     gft= (GifFileType *)malloc( sizeof(GifFileType) );
195     if  ( ! gft )
196 	{ XDEB(gft); return (GifFileType *)0;	}
197 
198     memset( gft, '\0', sizeof(GifFileType));
199 
200     strncpy( gft->gftVersionString, GIF87_STAMP, 6 )[6]= '\0';
201 
202     gft->gftSis= sis;
203     gft->gftSisBlocked= (SimpleInputStream *)0;
204     gft->gftSisLzw= (SimpleInputStream *)0;
205 
206     /* Lets see if this is a GIF file: */
207     if  ( sioInReadBytes( gft->gftSis,
208 			    (unsigned char *)gft->gftVersionString, 6 ) != 6 )
209 	{
210 	LDEB(6);
211         _GifError= D_GIF_ERR_READ_FAILED;
212         free( gft );
213         return (GifFileType *)0;
214 	}
215 
216     if  ( strcmp( gft->gftVersionString, GIF87_STAMP )	&&
217 	  strcmp( gft->gftVersionString, GIF89_STAMP )	)
218 	{
219 	SDEB(gft->gftVersionString);
220         _GifError= D_GIF_ERR_NOT_GIF_FILE;
221         free( gft );
222         return (GifFileType *)0;
223 	}
224 
225     if  ( bmGifReadScreenDescriptor( gft ) == GIF_ERROR )
226 	{
227 	LDEB(1);
228         free( gft );
229         return (GifFileType *)0;
230 	}
231 
232     _GifError = 0;
233 
234     return gft;
235 }
236 
237 /******************************************************************************
238 *   This routine should be called before any attemp to read an image.         *
239 ******************************************************************************/
240 
bmGifGetRecordType(GifFileType * gft,GifRecordType * Type)241 int bmGifGetRecordType(GifFileType *gft, GifRecordType *Type)
242 {
243     unsigned char		c;
244 
245     /*  1  */
246     if  ( ! gft->gftSis )
247 	{
248 	XDEB(gft->gftSis);
249 	_GifError= D_GIF_ERR_NOT_READABLE;
250 	return GIF_ERROR;
251 	}
252 
253     c= sioInGetByte( gft->gftSis );
254 
255     switch( c )
256 	{
257 	case ',':
258 	    *Type= IMAGE_DESC_RECORD_TYPE;
259 	    break;
260 
261 	case '!':
262 	    *Type= EXTENSION_RECORD_TYPE;
263 	    break;
264 
265 	case ';':
266 	    *Type= TERMINATE_RECORD_TYPE;
267 	    break;
268 
269 	default:
270 	    CDEB(c);
271 	    *Type= UNDEFINED_RECORD_TYPE;
272 	    _GifError = D_GIF_ERR_WRONG_RECORD;
273 	    return GIF_ERROR;
274 	}
275 
276     return GIF_OK;
277 }
278 
279 /************************************************************************/
280 /*									*/
281 /*  Read an image descriptor from the input file.			*/
282 /*  NOTE that it is assumed the Image desc. header (',') has been read.	*/
283 /*									*/
284 /*  1)  Opened for reading?						*/
285 /*  2)  Read image geometry.						*/
286 /*  3)  Get image flag bits.						*/
287 /*  4)  Does the image have its own palette.. If so read it.		*/
288 /*									*/
289 /************************************************************************/
290 
DGifGetImageDesc(GifFileType * gft)291 int DGifGetImageDesc(	GifFileType *	gft )
292 {
293     int				bitsPerPixel;
294     GifByteType			Buf[3];
295     GifImageDesc *		gid= &(gft->gftCurrentImageDescriptor);
296 
297     /*  1  */
298     if  ( ! gft->gftSis )
299 	{
300 	XDEB(gft->gftSis);
301 	_GifError= D_GIF_ERR_NOT_READABLE;
302 	return GIF_ERROR;
303 	}
304 
305     /*  2  */
306     gid->Left= sioEndianGetLeInt16( gft->gftSis );
307     gid->Top= sioEndianGetLeInt16( gft->gftSis );
308     gid->Width= sioEndianGetLeInt16( gft->gftSis );
309     gid->Height= sioEndianGetLeInt16( gft->gftSis );
310 
311     /*  3  */
312     Buf[0]= sioInGetByte( gft->gftSis );
313 
314     bitsPerPixel= (Buf[0] & 0x07) + 1;
315     gid->Interlace= (Buf[0] & 0x40);
316 
317     bmGifInitGifColorMap( &(gid->gidImageColorMap) );
318 
319     /*  4  */
320     if  ( Buf[0] & 0x80 )
321 	{
322 	if  ( bmGifReadColorMap( gft, &(gid->gidImageColorMap),
323 							    bitsPerPixel ) )
324 	    { LDEB(bitsPerPixel); return GIF_ERROR;	}
325 	}
326 
327     gft->gftPixelCount= (long)gid->Width *(long)gid->Height;
328 
329     DGifSetupDecompress( gft );  /* Reset decompress algorithm parameters. */
330 
331     return GIF_OK;
332 }
333 
334 /************************************************************************/
335 /*									*/
336 /*  Get one full scanned line (buffer) of length count from GIF file.	*/
337 /*									*/
338 /*  3)  The image is finished.. Close (and drain) to blocked input	*/
339 /*	stream.								*/
340 /*									*/
341 /************************************************************************/
342 
bmGifGetPixels(GifFileType * gft,int * pFoundTransparent,unsigned char * buffer,int count,int transparentColor)343 int bmGifGetPixels(	GifFileType *	gft,
344 			int *		pFoundTransparent,
345 			unsigned char *	buffer,
346 			int		count,
347 			int		transparentColor )
348 {
349     if  ( ! gft->gftSis )
350 	{
351 	XDEB(gft->gftSis);
352 	_GifError= D_GIF_ERR_NOT_READABLE;
353 	return GIF_ERROR;
354 	}
355 
356     if  ( count > gft->gftPixelCount )
357 	{
358 	LLDEB(count,gft->gftPixelCount);
359 	_GifError = D_GIF_ERR_DATA_TOO_BIG;
360 	return GIF_ERROR;
361 	}
362 
363     gft->gftPixelCount -= count;
364 
365     if  ( sioInReadBytes( gft->gftSisLzw, buffer, count ) == count )
366 	{
367 	if  ( transparentColor >= 0 && ! *pFoundTransparent )
368 	    {
369 	    int		i;
370 
371 	    for ( i= 0; i < count; i++ )
372 		{
373 		if  ( buffer[i] == transparentColor )
374 		    { *pFoundTransparent= 1;	}
375 		}
376 	    }
377 
378 	if  ( gft->gftPixelCount == 0 )
379 	    { bmGifCleanupDecompress( gft );	}
380 
381 	return GIF_OK;
382 	}
383     else{ LDEB(count); return GIF_ERROR;	}
384 }
385 
386 /************************************************************************/
387 /*									*/
388 /*  Get an extension block (see GIF manual) from gif file. This		*/
389 /*  routine only returns the first data block, and			*/
390 /*  DGifGetExtensionNext shouldbe called after this one until NULL	*/
391 /*  extension is returned.						*/
392 /*  The Extension should NOT be freed by the user (not dynamically	*/
393 /*  allocated).								*/
394 /*  Note it is assumed the Extension desc. header ('!') has been read.	*/
395 /*									*/
396 /************************************************************************/
397 
DGifGetExtension(GifFileType * gft,int * ExtCode,GifByteType Extension[256])398 int DGifGetExtension(	GifFileType *		gft,
399 			int *			ExtCode,
400 			GifByteType		Extension[256] )
401 {
402     GifByteType			Buf;
403     int				got;
404 
405     if  ( ! gft->gftSis )
406 	{
407 	XDEB(gft->gftSis);
408 	_GifError= D_GIF_ERR_NOT_READABLE;
409 	return GIF_ERROR;
410 	}
411 
412     Buf= sioInGetByte( gft->gftSis );
413 
414     *ExtCode= Buf;
415 
416     if  ( DGifGetExtensionNext( gft, &got, Extension) != GIF_OK )
417 	{ LDEB(1); return GIF_ERROR;	}
418     if  ( ! got )
419 	{ LDEB(got); return GIF_ERROR;	}
420 
421     return GIF_OK;
422 }
423 
424 /************************************************************************/
425 /*									*/
426 /*  Get a following extension block (see GIF manual) from gif file.	*/
427 /*  This routine should be called until NULL Extension is returned.	*/
428 /*  The Extension should NOT be freed by the user (not dynamically	*/
429 /*  allocated).								*/
430 /*									*/
431 /************************************************************************/
432 
DGifGetExtensionNext(GifFileType * gft,int * pGot,GifByteType Extension[256])433 int DGifGetExtensionNext(	GifFileType *	gft,
434 				int *		pGot,
435 				GifByteType	Extension[256] )
436 {
437     int				byte;
438 
439     byte= sioInGetByte( gft->gftSis );
440     if  ( byte == EOF )
441 	{
442 	XDEB(byte);
443 	_GifError = D_GIF_ERR_READ_FAILED;
444 	return GIF_ERROR;
445 	}
446 
447     if  ( byte == 0 )
448 	{ *pGot= 0; return GIF_OK; }
449 
450     if  ( sioInReadBytes( gft->gftSis, Extension+ 1, byte ) != byte )
451 	{
452 	LDEB(byte);
453 	_GifError = D_GIF_ERR_READ_FAILED; return GIF_ERROR;
454 	}
455     *pGot= 1;
456     Extension[0]= byte;
457     return GIF_OK;
458 }
459 
460 /************************************************************************/
461 /*									*/
462 /*  Close a gif file that was opened for reading: Do the necessary	*/
463 /*  cleanup.								*/
464 /*									*/
465 /************************************************************************/
466 
DGifCloseFile(GifFileType * gft)467 int DGifCloseFile(GifFileType *gft)
468 {
469     if (gft == NULL) return GIF_ERROR;
470 
471     if  ( ! gft->gftSis )
472 	{
473 	XDEB(gft->gftSis);
474 	_GifError= D_GIF_ERR_NOT_READABLE;
475 	return GIF_ERROR;
476 	}
477 
478     bmGifCleanupDecompress( gft );
479 
480     free(gft);
481 
482     return GIF_OK;
483 }
484 
485