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