1 /******************************************************************************
2 *   "Gif-Lib" - Yet another gif library.				      *
3 *									      *
4 * Written by:  Gershon Elber				Ver 1.1, Aug. 1990    *
5 *******************************************************************************
6 * The kernel of the GIF Encoding process can be found here.		      *
7 *******************************************************************************
8 * History:								      *
9 * 14 Jun 89 - Version 1.0 by Gershon Elber.				      *
10 *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
11 * 26 Jun 96 - Version 3.0 by Eric S. Raymond (Full GIF89 support)
12 ******************************************************************************/
13 
14 #ifdef _WIN32
15 #include "../win32/config.h"
16 #else
17 #include "../config.h"
18 #endif
19 
20 #ifdef __MSDOS__
21 #include <alloc.h>
22 #include <sys\stat.h>
23 #else
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #ifdef R6000
27 /* FIXME: What is sys/mode.h?  Can we substitute a check for this file rather
28  * than a check based on machine type?
29  */
30 #include <sys/mode.h>
31 #endif
32 #endif /* __MSDOS__ */
33 
34 #include <fcntl.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #include <stdio.h>
42 #include <string.h>
43 #include "gif_lib.h"
44 #include "gif_lib_private.h"
45 
46 /* #define DEBUG_NO_PREFIX		          Dump only compressed data. */
47 
48 /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
49 static GifPixelType CodeMask[] = {
50     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
51 };
52 
53 static unsigned char GifVersionPrefix[GIF_STAMP_LEN + 1] = GIF87_STAMP;
54 static int GifVersionPrefixLen = GIF_STAMP_LEN ;
55 
56 #define WRITE(_gif,_buf,_len)   \
57   (((GifFilePrivateType*)_gif->Private)->Write ?    \
58    ((GifFilePrivateType*)_gif->Private)->Write(_gif,(unsigned char *)_buf,(int)_len) :    \
59    fwrite(_buf, 1, _len, ((GifFilePrivateType*)_gif->Private)->File))
60 
61 static int EGifPutWord(int Word, GifFileType *GifFile);
62 static int EGifSetupCompress(GifFileType *GifFile);
63 static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
64 								int LineLen);
65 static int EGifCompressOutput(GifFileType *GifFile, int Code);
66 static int EGifBufferedOutput(GifFileType *GifFile, GifByteType *Buf, int c);
67 
68 /******************************************************************************
69 *   Update a new gif file, given its file handle, which must be opened for    *
70 * write in binary mode.							      *
71 *   Returns GifFileType pointer dynamically allocated which serves as the gif *
72 * info record. _GifError is cleared if succesfull.			      *
73 ******************************************************************************/
EGifOpenFileHandle(int FileHandle)74 GifFileType *EGifOpenFileHandle(int FileHandle)
75 {
76     GifFileType *GifFile;
77     GifFilePrivateType *Private;
78     FILE *f;
79 
80     if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
81         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
82         return NULL;
83     }
84 
85     memset(GifFile, '\0', sizeof(GifFileType));
86 
87     if ((Private = (GifFilePrivateType *)
88                    malloc(sizeof(GifFilePrivateType))) == NULL) {
89         free(GifFile);
90         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
91         return NULL;
92     }
93     if ((Private->HashTable = _InitHashTable()) == NULL) {
94         free(GifFile);
95         free(Private);
96         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
97         return NULL;
98     }
99 
100 #ifdef __MSDOS__
101     setmode(FileHandle, O_BINARY);      /* Make sure it is in binary mode. */
102 #endif /* __MSDOS__ */
103 
104     f = fdopen(FileHandle, "wb");           /* Make it into a stream: */
105 
106 #ifdef __MSDOS__
107     setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);   /* And inc. stream buffer. */
108 #endif /* __MSDOS__ */
109 
110     GifFile->Private = (VoidPtr) Private;
111     Private->FileHandle = FileHandle;
112     Private->File = f;
113     Private->FileState = FILE_STATE_WRITE;
114 
115     Private->Write = (OutputFunc)0; /* No user write routine (MRB) */
116     GifFile->UserData = (VoidPtr)0; /* No user write handle (MRB) */
117 
118     _GifError = 0;
119 
120     return GifFile;
121 }
122 
123 /******************************************************************************
124 * Output constructor that takes user supplied output function.                *
125 * Basically just a copy of EGifOpenFileHandle. (MRB)                          *
126 ******************************************************************************/
EGifOpen(void * userData,OutputFunc writeFunc)127 GifFileType* EGifOpen(void* userData, OutputFunc writeFunc)
128 {
129     GifFileType* GifFile;
130     GifFilePrivateType* Private;
131 
132      if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) {
133         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
134         return NULL;
135     }
136 
137     memset(GifFile, '\0', sizeof(GifFileType));
138 
139     if ((Private = (GifFilePrivateType *)
140                    malloc(sizeof(GifFilePrivateType))) == NULL) {
141         free(GifFile);
142         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
143         return NULL;
144     }
145 
146     Private->HashTable = _InitHashTable();
147     if (Private->HashTable == NULL) {
148         free (GifFile);
149         free (Private);
150         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
151         return NULL;
152     }
153 
154     GifFile->Private = (VoidPtr) Private;
155     Private->FileHandle = 0;
156     Private->File = (FILE *)0;
157     Private->FileState = FILE_STATE_WRITE;
158 
159     Private->Write = writeFunc; /* User write routine (MRB) */
160     GifFile->UserData = userData; /* User write handle (MRB) */
161 
162     _GifError = 0;
163 
164     return GifFile;
165 }
166 
167 /******************************************************************************
168 *   Routine to set current GIF version. All files open for write will be      *
169 * using this version until next call to this routine. Version consists of     *
170 * 3 characters as "87a" or "89a". No test is made to validate the version.    *
171 ******************************************************************************/
EGifSetGifVersion(const char * Version)172 void EGifSetGifVersion(const char *Version)
173 {
174     memcpy(GifVersionPrefix + GIF_VERSION_POS, Version, 3);
175 }
176 
177 /******************************************************************************
178 *   This routine should be called before any other EGif calls, immediately    *
179 * follows the GIF file openning.					      *
180 ******************************************************************************/
EGifPutScreenDesc(GifFileType * GifFile,int Width,int Height,int ColorRes,int BackGround,const ColorMapObject * ColorMap)181 int EGifPutScreenDesc(GifFileType *GifFile,
182 	int Width, int Height, int ColorRes, int BackGround,
183 	const ColorMapObject *ColorMap)
184 {
185     int i;
186     GifByteType Buf[3];
187     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
188 
189     if (Private->FileState & FILE_STATE_SCREEN) {
190 	/* If already has screen descriptor - something is wrong! */
191 	_GifError = E_GIF_ERR_HAS_SCRN_DSCR;
192 	return GIF_ERROR;
193     }
194     if (!IS_WRITEABLE(Private)) {
195 	/* This file was NOT open for writing: */
196 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
197 	return GIF_ERROR;
198     }
199 
200 /* First write the version prefix into the file. */
201 #ifndef DEBUG_NO_PREFIX
202     if (WRITE(GifFile, GifVersionPrefix, GifVersionPrefixLen) !=
203 						GifVersionPrefixLen) {
204 	_GifError = E_GIF_ERR_WRITE_FAILED;
205 	return GIF_ERROR;
206     }
207 #endif /* DEBUG_NO_PREFIX */
208 
209     GifFile->SWidth = Width;
210     GifFile->SHeight = Height;
211     GifFile->SColorResolution = ColorRes;
212     GifFile->SBackGroundColor = BackGround;
213     if(ColorMap)
214 	{
215 		GifFile->SColorMap=MakeMapObject(ColorMap->ColorCount,ColorMap->Colors);
216 
217         if (GifFile->SColorMap == NULL)
218 		{
219             _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
220             return GIF_ERROR;
221         }
222     }else
223       GifFile->SColorMap=NULL;
224 
225     /* Put the screen descriptor into the file: */
226     EGifPutWord(Width, GifFile);
227     EGifPutWord(Height, GifFile);
228 	if( ColorMap )
229     	Buf[0] = 0x80 | ((ColorRes - 1) << 4) |	(ColorMap->BitsPerPixel - 1);
230 	else
231     	Buf[0] = 0x00 | ((ColorRes - 1) << 4) ;
232     Buf[1] = BackGround;
233     Buf[2] = 0;
234 #ifndef DEBUG_NO_PREFIX
235     WRITE(GifFile, Buf, 3);
236 #endif /* DEBUG_NO_PREFIX */
237 
238     /* If we have Global color map - dump it also: */
239 #ifndef DEBUG_NO_PREFIX
240     if (ColorMap != NULL)
241 	for (i = 0; i < ColorMap->ColorCount; i++) {
242 	    /* Put the ColorMap out also: */
243 	    Buf[0] = ColorMap->Colors[i].Red;
244 	    Buf[1] = ColorMap->Colors[i].Green;
245 	    Buf[2] = ColorMap->Colors[i].Blue;
246 	    if (WRITE(GifFile, Buf, 3) != 3) {
247 	        _GifError = E_GIF_ERR_WRITE_FAILED;
248 		return GIF_ERROR;
249 	    }
250 	}
251 #endif /* DEBUG_NO_PREFIX */
252 
253     /* Mark this file as has screen descriptor, and no pixel written yet: */
254     Private->FileState |= FILE_STATE_SCREEN;
255 
256     return GIF_OK;
257 }
258 
259 /******************************************************************************
260 *   This routine should be called before any attemp to dump an image - any    *
261 * call to any of the pixel dump routines.				      *
262 ******************************************************************************/
EGifPutImageDesc(GifFileType * GifFile,int Left,int Top,int Width,int Height,int Interlace,const ColorMapObject * ColorMap)263 int EGifPutImageDesc(GifFileType *GifFile,
264 	int Left, int Top, int Width, int Height, int Interlace,
265 	const ColorMapObject *ColorMap)
266 {
267     int i;
268     GifByteType Buf[3];
269     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
270 
271     if (Private->FileState & FILE_STATE_IMAGE &&
272 #if defined(__MSDOS__) || defined(__GNUC__)
273 	Private->PixelCount > 0xffff0000UL) {
274 #else
275 	Private->PixelCount > 0xffff0000) {
276 #endif /* __MSDOS__ */
277 	/* If already has active image descriptor - something is wrong! */
278 	_GifError = E_GIF_ERR_HAS_IMAG_DSCR;
279 	return GIF_ERROR;
280     }
281     if (!IS_WRITEABLE(Private)) {
282 	/* This file was NOT open for writing: */
283 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
284 	return GIF_ERROR;
285     }
286     GifFile->Image.Left = Left;
287     GifFile->Image.Top = Top;
288     GifFile->Image.Width = Width;
289     GifFile->Image.Height = Height;
290     GifFile->Image.Interlace = Interlace;
291     if(ColorMap)
292 	{
293       GifFile->Image.ColorMap =MakeMapObject(ColorMap->ColorCount,ColorMap->Colors);
294         if (GifFile->Image.ColorMap == NULL)
295 		{
296             _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
297             return GIF_ERROR;
298         }
299     }else
300       GifFile->Image.ColorMap = NULL;
301 
302     /* Put the image descriptor into the file: */
303     Buf[0] = ',';			       /* Image seperator character. */
304 #ifndef DEBUG_NO_PREFIX
305     WRITE(GifFile, Buf, 1);
306 #endif /* DEBUG_NO_PREFIX */
307     EGifPutWord(Left, GifFile);
308     EGifPutWord(Top, GifFile);
309     EGifPutWord(Width, GifFile);
310     EGifPutWord(Height, GifFile);
311     Buf[0] = (ColorMap ? 0x80 : 0x00) |
312 	  (Interlace ? 0x40 : 0x00) |
313 	  (ColorMap ? ColorMap->BitsPerPixel - 1 : 0);
314 #ifndef DEBUG_NO_PREFIX
315     WRITE(GifFile, Buf, 1);
316 #endif /* DEBUG_NO_PREFIX */
317 
318     /* If we have Global color map - dump it also: */
319 #ifndef DEBUG_NO_PREFIX
320     if (ColorMap != NULL)
321 	for (i = 0; i < ColorMap->ColorCount; i++) {
322 	    /* Put the ColorMap out also: */
323 	    Buf[0] = ColorMap->Colors[i].Red;
324 	    Buf[1] = ColorMap->Colors[i].Green;
325 	    Buf[2] = ColorMap->Colors[i].Blue;
326 	    if (WRITE(GifFile, Buf, 3) != 3) {
327 	        _GifError = E_GIF_ERR_WRITE_FAILED;
328 		return GIF_ERROR;
329 	    }
330 	}
331 #endif /* DEBUG_NO_PREFIX */
332     if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL)
333     {
334 	_GifError = E_GIF_ERR_NO_COLOR_MAP;
335 	return GIF_ERROR;
336     }
337 
338     /* Mark this file as has screen descriptor: */
339     Private->FileState |= FILE_STATE_IMAGE;
340     Private->PixelCount = (long) Width * (long) Height;
341 
342     EGifSetupCompress(GifFile);      /* Reset compress algorithm parameters. */
343 
344     return GIF_OK;
345 }
346 
347 /******************************************************************************
348 *  Put one full scanned line (Line) of length LineLen into GIF file.	      *
349 ******************************************************************************/
350 int EGifPutLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
351 {
352     int i;
353     GifPixelType Mask;
354     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
355 
356     if (!IS_WRITEABLE(Private)) {
357 	/* This file was NOT open for writing: */
358 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
359 	return GIF_ERROR;
360     }
361 
362     if (!LineLen)
363       LineLen = GifFile->Image.Width;
364     if (Private->PixelCount < (unsigned)LineLen) {
365 	_GifError = E_GIF_ERR_DATA_TOO_BIG;
366 	return GIF_ERROR;
367     }
368     Private->PixelCount -= LineLen;
369 
370     /* Make sure the codes are not out of bit range, as we might generate    */
371     /* wrong code (because of overflow when we combine them) in this case:   */
372     Mask = CodeMask[Private->BitsPerPixel];
373     for (i = 0; i < LineLen; i++) Line[i] &= Mask;
374 
375     return EGifCompressLine(GifFile, Line, LineLen);
376 }
377 
378 /******************************************************************************
379 * Put a comment into GIF file using the GIF89 comment extension block.        *
380 ******************************************************************************/
381 int EGifPutComment(GifFileType *GifFile, const char *Comment)
382 {
383     unsigned int length = strlen(Comment);
384     char *buf;
385 
386     length = strlen(Comment);
387     if (length <= 255) {
388         return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE,
389                                 length, Comment);
390     } else {
391         buf = (char *)Comment;
392         if (EGifPutExtensionFirst(GifFile, COMMENT_EXT_FUNC_CODE, 255, buf)
393                 == GIF_ERROR) {
394             return GIF_ERROR;
395         }
396         length -= 255;
397         buf = buf + 255;
398 
399         /* Break the comment into 255 byte sub blocks */
400         while (length > 255) {
401             if (EGifPutExtensionNext(GifFile, 0, 255, buf) == GIF_ERROR) {
402                 return GIF_ERROR;
403             }
404             buf = buf + 255;
405             length -= 255;
406         }
407         /* Output any partial block and the clear code. */
408         if (length > 0) {
409             if (EGifPutExtensionLast(GifFile, 0, length, buf) == GIF_ERROR) {
410                 return GIF_ERROR;
411             }
412         } else {
413             if (EGifPutExtensionLast(GifFile, 0, 0, NULL) == GIF_ERROR) {
414                 return GIF_ERROR;
415             }
416         }
417     }
418     return GIF_OK;
419 }
420 
421 /******************************************************************************
422 *   Put a first extension block (see GIF manual) into gif file.  Here more    *
423 * extensions can be dumped using EGifPutExtensionMid until		      *
424 * EGifPutExtensionLast is invoked.					      *
425 ******************************************************************************/
426 int EGifPutExtensionFirst(GifFileType *GifFile, int ExtCode, int ExtLen,
427 							const VoidPtr Extension)
428 {
429     GifByteType Buf[3];
430     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
431 
432     if (!IS_WRITEABLE(Private)) {
433 	/* This file was NOT open for writing: */
434 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
435 	return GIF_ERROR;
436     }
437 
438     if (ExtCode == 0)
439 	fwrite(&ExtLen, 1, 1, Private->File);
440     else
441     {
442 	Buf[0] = '!';
443 	Buf[1] = ExtCode;
444 	Buf[2] = ExtLen;
445 	fwrite(Buf, 1, 3, Private->File);
446     }
447     fwrite(Extension, 1, ExtLen, Private->File);
448 
449     return GIF_OK;
450 }
451 
452 /******************************************************************************
453 *   Put a middle extension block (see GIF manual) into gif file.	      *
454 ******************************************************************************/
455 int EGifPutExtensionNext(GifFileType *GifFile, int ExtCode, int ExtLen,
456 							const VoidPtr Extension)
457 {
458     GifByteType Buf;
459     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
460 
461     if (!IS_WRITEABLE(Private)) {
462 	/* This file was NOT open for writing: */
463 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
464 	return GIF_ERROR;
465     }
466 
467     Buf = ExtLen;
468     fwrite(&Buf, 1, 1, Private->File);
469     fwrite(Extension, 1, ExtLen, Private->File);
470 
471     return GIF_OK;
472 }
473 
474 /******************************************************************************
475 *   Put a last extension block (see GIF manual) into gif file.		      *
476 ******************************************************************************/
477 int EGifPutExtensionLast(GifFileType *GifFile, int ExtCode, int ExtLen,
478 							const VoidPtr Extension)
479 {
480     GifByteType Buf;
481     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
482 
483     if (!IS_WRITEABLE(Private)) {
484 	/* This file was NOT open for writing: */
485 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
486 	return GIF_ERROR;
487     }
488 
489     /* If we are given an extension sub-block output it now. */
490     if (ExtLen > 0)
491 	{
492     	Buf = ExtLen;
493 	    fwrite(&Buf, 1, 1, Private->File);
494     	fwrite(Extension, 1, ExtLen, Private->File);
495 	}
496 
497     Buf = 0;
498     fwrite(&Buf, 1, 1, Private->File);
499 
500     return GIF_OK;
501 }
502 
503 /******************************************************************************
504 *   Put an extension block (see GIF manual) into gif file.		      *
505 ******************************************************************************/
506 int EGifPutExtension(GifFileType *GifFile, int ExtCode, int ExtLen,
507 						  const VoidPtr Extension)
508 {
509     GifByteType Buf[3];
510     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
511 
512     if (!IS_WRITEABLE(Private)) {
513 	    /* This file was NOT open for writing: */
514 	    _GifError = E_GIF_ERR_NOT_WRITEABLE;
515 	    return GIF_ERROR;
516     }
517 
518     if (ExtCode == 0)
519         WRITE(GifFile, (GifByteType*)&ExtLen, 1);
520     else {
521 	    Buf[0] = '!';
522 	    Buf[1] = ExtCode;
523 	    Buf[2] = ExtLen;
524         WRITE(GifFile, Buf, 3);
525     }
526     WRITE(GifFile, Extension, ExtLen);
527     Buf[0] = 0;
528     WRITE(GifFile, Buf, 1);
529 
530     return GIF_OK;
531 }
532 
533 /******************************************************************************
534 *   This routine should be called last, to close GIF file.		      *
535 ******************************************************************************/
536 int EGifCloseFile(GifFileType *GifFile)
537 {
538     GifByteType Buf;
539     GifFilePrivateType *Private;
540     FILE *File;
541 
542     if (GifFile == NULL) return GIF_ERROR;
543 
544     Private = (GifFilePrivateType *) GifFile->Private;
545     if (!IS_WRITEABLE(Private)) {
546 	/* This file was NOT open for writing: */
547 	_GifError = E_GIF_ERR_NOT_WRITEABLE;
548 	return GIF_ERROR;
549     }
550 
551     File = Private->File;
552 
553     Buf = ';';
554     WRITE(GifFile, &Buf, 1);
555 
556     if (GifFile->Image.ColorMap) {
557         FreeMapObject(GifFile->Image.ColorMap);
558         GifFile->Image.ColorMap = NULL;
559     }
560     if (GifFile->SColorMap) {
561         FreeMapObject(GifFile->SColorMap);
562         GifFile->SColorMap = NULL;
563     }
564     if (Private) {
565         if (Private->HashTable) {
566             free((char *) Private->HashTable);
567         }
568 	    free((char *) Private);
569     }
570     free(GifFile);
571 
572     if (File && fclose(File) != 0)
573 	{
574 		_GifError = E_GIF_ERR_CLOSE_FAILED;
575 		return GIF_ERROR;
576     }
577     return GIF_OK;
578 }
579 
580 /******************************************************************************
581 *   Put 2 bytes (word) into the given file:				      *
582 ******************************************************************************/
583 static int EGifPutWord(int Word, GifFileType *GifFile)
584 {
585     unsigned char c[2];
586 
587     c[0] = Word & 0xff;
588     c[1] = (Word >> 8) & 0xff;
589 #ifndef DEBUG_NO_PREFIX
590     if (WRITE(GifFile, c, 2) == 2)
591         return GIF_OK;
592     else
593         return GIF_ERROR;
594 #else
595     return GIF_OK;
596 #endif /* DEBUG_NO_PREFIX */
597 }
598 
599 /******************************************************************************
600 *   Setup the LZ compression for this image:				      *
601 ******************************************************************************/
602 static int EGifSetupCompress(GifFileType *GifFile)
603 {
604     int BitsPerPixel;
605     GifByteType Buf;
606     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
607 
608     /* Test and see what color map to use, and from it # bits per pixel: */
609     if (GifFile->Image.ColorMap)
610 	BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel;
611     else if (GifFile->SColorMap)
612 	BitsPerPixel = GifFile->SColorMap->BitsPerPixel;
613     else {
614 	_GifError = E_GIF_ERR_NO_COLOR_MAP;
615 	return GIF_ERROR;
616     }
617 
618     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
619     WRITE(GifFile, &Buf, 1);     /* Write the Code size to file. */
620 
621     Private->Buf[0] = 0;			  /* Nothing was output yet. */
622     Private->BitsPerPixel = BitsPerPixel;
623     Private->ClearCode = (1 << BitsPerPixel);
624     Private->EOFCode = Private->ClearCode + 1;
625     Private->RunningCode = Private->EOFCode + 1;
626     Private->RunningBits = BitsPerPixel + 1;	 /* Number of bits per code. */
627     Private->MaxCode1 = 1 << Private->RunningBits;	   /* Max. code + 1. */
628     Private->CrntCode = FIRST_CODE;	   /* Signal that this is first one! */
629     Private->CrntShiftState = 0;      /* No information in CrntShiftDWord. */
630     Private->CrntShiftDWord = 0;
631 
632        /* Clear hash table and send Clear to make sure the decoder do the same. */
633     _ClearHashTable(Private->HashTable);
634 
635 	/* Send Clear to make sure the encoder is initialized. */
636     if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR)
637 	{
638 		_GifError = E_GIF_ERR_DISK_IS_FULL;
639 		return GIF_ERROR;
640     }
641     return GIF_OK;
642 }
643 
644 /******************************************************************************
645 *   The LZ compression routine:						      *
646 *   This version compress the given buffer Line of length LineLen.	      *
647 *   This routine can be called few times (one per scan line, for example), in *
648 * order the complete the whole image.					      *
649 ******************************************************************************/
650 static int EGifCompressLine(GifFileType *GifFile, GifPixelType *Line,
651 								int LineLen)
652 {
653     int i = 0, CrntCode, NewCode;
654 	unsigned long NewKey;
655 	GifPixelType Pixel;
656     GifHashTableType *HashTable;
657 	GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
658 
659         HashTable = Private->HashTable;
660 
661     if (Private->CrntCode == FIRST_CODE)    /* Its first time! */
662         CrntCode = Line[i++];
663     else
664         CrntCode = Private->CrntCode;    /* Get last code in compression. */
665 
666     while (i < LineLen) {   /* Decode LineLen items. */
667         Pixel = Line[i++];  /* Get next pixel from stream. */
668         /* Form a new unique key to search hash table for the code combines
669          * CrntCode as Prefix string with Pixel as postfix char.
670          */
671         NewKey = (((UINT32) CrntCode) << 8) + Pixel;
672         if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
673             /* This Key is already there, or the string is old one, so
674              * simple take new code as our CrntCode:
675              */
676             CrntCode = NewCode;
677         } else {
678             /* Put it in hash table, output the prefix code, and make our
679              * CrntCode equal to Pixel.
680              */
681             if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
682                 _GifError = E_GIF_ERR_DISK_IS_FULL;
683                 return GIF_ERROR;
684             }
685             CrntCode = Pixel;
686 
687             /* If however the HashTable if full, we send a clear first and
688              * Clear the hash table.
689              */
690             if (Private->RunningCode >= LZ_MAX_CODE) {
691                 /* Time to do some clearance: */
692                 if (EGifCompressOutput(GifFile, Private->ClearCode)
693                         == GIF_ERROR) {
694                     _GifError = E_GIF_ERR_DISK_IS_FULL;
695                     return GIF_ERROR;
696                 }
697                 Private->RunningCode = Private->EOFCode + 1;
698                 Private->RunningBits = Private->BitsPerPixel + 1;
699                 Private->MaxCode1 = 1 << Private->RunningBits;
700                 _ClearHashTable(HashTable);
701             } else {
702                 /* Put this unique key with its relative Code in hash table: */
703                 _InsertHashTable(HashTable, NewKey, Private->RunningCode++);
704             }
705         }
706 
707     }
708 
709     /* Preserve the current state of the compression algorithm: */
710     Private->CrntCode = CrntCode;
711 
712     if (Private->PixelCount == 0) {
713         /* We are done - output last Code and flush output buffers: */
714         if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
715             _GifError = E_GIF_ERR_DISK_IS_FULL;
716             return GIF_ERROR;
717         }
718         if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) {
719             _GifError = E_GIF_ERR_DISK_IS_FULL;
720             return GIF_ERROR;
721         }
722         if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) {
723             _GifError = E_GIF_ERR_DISK_IS_FULL;
724             return GIF_ERROR;
725         }
726     }
727 
728     return GIF_OK;
729 }
730 
731 /******************************************************************************
732 *   The LZ compression output routine:                                        *
733 *   This routine is responsible for the compression of the bit stream into    *
734 *   8 bits (bytes) packets.                                                   *
735 *   Returns GIF_OK if written succesfully.                                    *
736 ******************************************************************************/
737 static int EGifCompressOutput(GifFileType *GifFile, int Code)
738 {
739     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
740     int retval = GIF_OK;
741 
742     if (Code == FLUSH_OUTPUT) {
743 		while (Private->CrntShiftState > 0) {
744 	    	/* Get Rid of what is left in DWord, and flush it. */
745 	    	if (EGifBufferedOutput(GifFile, Private->Buf,
746 			Private->CrntShiftDWord & 0xff) == GIF_ERROR)
747 		    	retval = GIF_ERROR;
748 	    	Private->CrntShiftDWord >>= 8;
749 	    	Private->CrntShiftState -= 8;
750 		}
751 		Private->CrntShiftState = 0;			   /* For next time. */
752 		if (EGifBufferedOutput(GifFile, Private->Buf,
753 	    	FLUSH_OUTPUT) == GIF_ERROR)
754     	        	retval = GIF_ERROR;
755     } else {
756 		Private->CrntShiftDWord |= ((long) Code) << Private->CrntShiftState;
757 		Private->CrntShiftState += Private->RunningBits;
758 		while (Private->CrntShiftState >= 8) {
759 	    	/* Dump out full bytes: */
760 	    	if (EGifBufferedOutput(GifFile, Private->Buf,
761 			Private->CrntShiftDWord & 0xff) == GIF_ERROR)
762 		    	retval = GIF_ERROR;
763 	    	Private->CrntShiftDWord >>= 8;
764 	    	Private->CrntShiftState -= 8;
765 		}
766     }
767 
768     /* If code cannt fit into RunningBits bits, must raise its size. Note */
769     /* however that codes above 4095 are used for special signaling.      */
770     if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {
771        Private->MaxCode1 = 1 << ++Private->RunningBits;
772     }
773 
774     return retval;
775 }
776 
777 /******************************************************************************
778 *   This routines buffers the given characters until 255 characters are ready *
779 * to be output. If Code is equal to -1 the buffer is flushed (EOF).	      *
780 *   The buffer is Dumped with first byte as its size, as GIF format requires. *
781 *   Returns GIF_OK if written succesfully.				      *
782 ******************************************************************************/
783 static int EGifBufferedOutput(GifFileType *GifFile, GifByteType *Buf, int c)
784 {
785     if (c == FLUSH_OUTPUT) {
786 	/* Flush everything out. */
787 	if (Buf[0] != 0 && WRITE(GifFile, Buf, Buf[0]+1) != (unsigned)(Buf[0] + 1))
788 	{
789 	    _GifError = E_GIF_ERR_WRITE_FAILED;
790 	    return GIF_ERROR;
791 	}
792 	/* Mark end of compressed data, by an empty block (see GIF doc): */
793 	Buf[0] = 0;
794 	if (WRITE(GifFile, Buf, 1) != 1)
795 	{
796 	    _GifError = E_GIF_ERR_WRITE_FAILED;
797 	    return GIF_ERROR;
798 	}
799     }
800     else {
801 	if (Buf[0] == 255) {
802 	    /* Dump out this buffer - it is full: */
803 	    if (WRITE(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1))
804 	    {
805 		_GifError = E_GIF_ERR_WRITE_FAILED;
806 		return GIF_ERROR;
807 	    }
808 	    Buf[0] = 0;
809 	}
810 	Buf[++Buf[0]] = c;
811     }
812 
813     return GIF_OK;
814 }
815 
816