1 /******************************************************************************
2
3 egif_lib.c - GIF encoding
4
5 The functions here and in dgif_lib.c are partitioned carefully so that
6 if you only require one of read and write capability, only one of these
7 two modules will be linked. Preserve this property!
8
9 *****************************************************************************/
10
11 #include <unistd.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <fcntl.h>
17
18 #ifdef _WIN32
19 #include <io.h>
20 #else
21 #include <sys/types.h>
22 #endif /* _WIN32 */
23 #include <sys/stat.h>
24
25 #include "gif_lib.h"
26 #include "gif_lib_private.h"
27
28 /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
29 /*@+charint@*/
30 static const GifPixelType CodeMask[] = {
31 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
32 };
33 /*@-charint@*/
34
35 static int EGifPutWord(int Word, GifFileType * GifFile);
36 static int EGifSetupCompress(GifFileType * GifFile);
37 static int EGifCompressLine(GifFileType * GifFile, GifPixelType * Line,
38 int LineLen);
39 static int EGifCompressOutput(GifFileType * GifFile, int Code);
40 static int EGifBufferedOutput(GifFileType * GifFile, GifByteType * Buf,
41 int c);
42
43 /* extract bytes from an unsigned word */
44 #define LOBYTE(x) ((x) & 0xff)
45 #define HIBYTE(x) (((x) >> 8) & 0xff)
46
47 /******************************************************************************
48 Open a new GIF file for write, specified by name. If TestExistance then
49 if the file exists this routines fails (returns NULL).
50 Returns a dynamically allocated GifFileType pointer which serves as the GIF
51 info record. The Error member is cleared if successful.
52 ******************************************************************************/
53 GifFileType *
EGifOpenFileName(const char * FileName,const bool TestExistence,int * Error)54 EGifOpenFileName(const char *FileName, const bool TestExistence, int *Error)
55 {
56
57 int FileHandle;
58 GifFileType *GifFile;
59
60 if (TestExistence)
61 /* android-changed: changed "S_IREAD | S_IWRITE" to "S_IRUSR | S_IWUSR" */
62 FileHandle = open(FileName, O_WRONLY | O_CREAT | O_EXCL,
63 S_IRUSR | S_IWUSR);
64 else
65 /* android-changed: changed "S_IREAD | S_IWRITE" to "S_IRUSR | S_IWUSR" */
66 FileHandle = open(FileName, O_WRONLY | O_CREAT | O_TRUNC,
67 S_IRUSR | S_IWUSR);
68
69 if (FileHandle == -1) {
70 if (Error != NULL)
71 *Error = E_GIF_ERR_OPEN_FAILED;
72 return NULL;
73 }
74 GifFile = EGifOpenFileHandle(FileHandle, Error);
75 if (GifFile == (GifFileType *) NULL)
76 (void)close(FileHandle);
77 return GifFile;
78 }
79
80 /******************************************************************************
81 Update a new GIF file, given its file handle, which must be opened for
82 write in binary mode.
83 Returns dynamically allocated a GifFileType pointer which serves as the GIF
84 info record.
85 Only fails on a memory allocation error.
86 ******************************************************************************/
87 GifFileType *
EGifOpenFileHandle(const int FileHandle,int * Error)88 EGifOpenFileHandle(const int FileHandle, int *Error)
89 {
90 GifFileType *GifFile;
91 GifFilePrivateType *Private;
92 FILE *f;
93
94 GifFile = (GifFileType *) malloc(sizeof(GifFileType));
95 if (GifFile == NULL) {
96 return NULL;
97 }
98
99 memset(GifFile, '\0', sizeof(GifFileType));
100
101 Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
102 if (Private == NULL) {
103 free(GifFile);
104 if (Error != NULL)
105 *Error = E_GIF_ERR_NOT_ENOUGH_MEM;
106 return NULL;
107 }
108 if ((Private->HashTable = _InitHashTable()) == NULL) {
109 free(GifFile);
110 free(Private);
111 if (Error != NULL)
112 *Error = E_GIF_ERR_NOT_ENOUGH_MEM;
113 return NULL;
114 }
115
116 #ifdef _WIN32
117 _setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
118 #endif /* _WIN32 */
119
120 f = fdopen(FileHandle, "wb"); /* Make it into a stream: */
121
122 GifFile->Private = (void *)Private;
123 Private->FileHandle = FileHandle;
124 Private->File = f;
125 Private->FileState = FILE_STATE_WRITE;
126
127 Private->Write = (OutputFunc) 0; /* No user write routine (MRB) */
128 GifFile->UserData = (void *)NULL; /* No user write handle (MRB) */
129
130 GifFile->Error = 0;
131
132 return GifFile;
133 }
134
135 /******************************************************************************
136 Output constructor that takes user supplied output function.
137 Basically just a copy of EGifOpenFileHandle. (MRB)
138 ******************************************************************************/
139 GifFileType *
EGifOpen(void * userData,OutputFunc writeFunc,int * Error)140 EGifOpen(void *userData, OutputFunc writeFunc, int *Error)
141 {
142 GifFileType *GifFile;
143 GifFilePrivateType *Private;
144
145 GifFile = (GifFileType *)malloc(sizeof(GifFileType));
146 if (GifFile == NULL) {
147 if (Error != NULL)
148 *Error = E_GIF_ERR_NOT_ENOUGH_MEM;
149 return NULL;
150 }
151
152 memset(GifFile, '\0', sizeof(GifFileType));
153
154 Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
155 if (Private == NULL) {
156 free(GifFile);
157 if (Error != NULL)
158 *Error = E_GIF_ERR_NOT_ENOUGH_MEM;
159 return NULL;
160 }
161
162 Private->HashTable = _InitHashTable();
163 if (Private->HashTable == NULL) {
164 free (GifFile);
165 free (Private);
166 if (Error != NULL)
167 *Error = E_GIF_ERR_NOT_ENOUGH_MEM;
168 return NULL;
169 }
170
171 GifFile->Private = (void *)Private;
172 Private->FileHandle = 0;
173 Private->File = (FILE *) 0;
174 Private->FileState = FILE_STATE_WRITE;
175
176 Private->Write = writeFunc; /* User write routine (MRB) */
177 GifFile->UserData = userData; /* User write handle (MRB) */
178
179 Private->gif89 = false; /* initially, write GIF87 */
180
181 GifFile->Error = 0;
182
183 return GifFile;
184 }
185
186 /******************************************************************************
187 Routine to compute the GIF version that will be written on output.
188 ******************************************************************************/
189 char *
EGifGetGifVersion(GifFileType * GifFile)190 EGifGetGifVersion(GifFileType *GifFile)
191 {
192 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
193 int i, j;
194
195 /*
196 * Bulletproofing - always write GIF89 if we need to.
197 * Note, we don't clear the gif89 flag here because
198 * users of the sequential API might have called EGifSetGifVersion()
199 * in order to set that flag.
200 */
201 for (i = 0; i < GifFile->ImageCount; i++) {
202 for (j = 0; j < GifFile->SavedImages[i].ExtensionBlockCount; j++) {
203 int function =
204 GifFile->SavedImages[i].ExtensionBlocks[j].Function;
205
206 if (function == COMMENT_EXT_FUNC_CODE
207 || function == GRAPHICS_EXT_FUNC_CODE
208 || function == PLAINTEXT_EXT_FUNC_CODE
209 || function == APPLICATION_EXT_FUNC_CODE)
210 Private->gif89 = true;
211 }
212 }
213 for (i = 0; i < GifFile->ExtensionBlockCount; i++) {
214 int function = GifFile->ExtensionBlocks[i].Function;
215
216 if (function == COMMENT_EXT_FUNC_CODE
217 || function == GRAPHICS_EXT_FUNC_CODE
218 || function == PLAINTEXT_EXT_FUNC_CODE
219 || function == APPLICATION_EXT_FUNC_CODE)
220 Private->gif89 = true;
221 }
222
223 if (Private->gif89)
224 return GIF89_STAMP;
225 else
226 return GIF87_STAMP;
227 }
228
229 /******************************************************************************
230 Set the GIF version. In the extremely unlikely event that there is ever
231 another version, replace the bool argument with an enum in which the
232 GIF87 value is 0 (numerically the same as bool false) and the GIF89 value
233 is 1 (numerically the same as bool true). That way we'll even preserve
234 object-file compatibility!
235 ******************************************************************************/
EGifSetGifVersion(GifFileType * GifFile,const bool gif89)236 void EGifSetGifVersion(GifFileType *GifFile, const bool gif89)
237 {
238 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
239
240 Private->gif89 = gif89;
241 }
242
243 /******************************************************************************
244 All writes to the GIF should go through this.
245 ******************************************************************************/
InternalWrite(GifFileType * GifFileOut,const unsigned char * buf,size_t len)246 static int InternalWrite(GifFileType *GifFileOut,
247 const unsigned char *buf, size_t len)
248 {
249 GifFilePrivateType *Private = (GifFilePrivateType*)GifFileOut->Private;
250 if (Private->Write)
251 return Private->Write(GifFileOut,buf,len);
252 else
253 return fwrite(buf, 1, len, Private->File);
254 }
255
256 /******************************************************************************
257 This routine should be called before any other EGif calls, immediately
258 following the GIF file opening.
259 ******************************************************************************/
260 int
EGifPutScreenDesc(GifFileType * GifFile,const int Width,const int Height,const int ColorRes,const int BackGround,const ColorMapObject * ColorMap)261 EGifPutScreenDesc(GifFileType *GifFile,
262 const int Width,
263 const int Height,
264 const int ColorRes,
265 const int BackGround,
266 const ColorMapObject *ColorMap)
267 {
268 GifByteType Buf[3];
269 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
270 char *write_version;
271
272 if (Private->FileState & FILE_STATE_SCREEN) {
273 /* If already has screen descriptor - something is wrong! */
274 GifFile->Error = E_GIF_ERR_HAS_SCRN_DSCR;
275 return GIF_ERROR;
276 }
277 if (!IS_WRITEABLE(Private)) {
278 /* This file was NOT open for writing: */
279 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
280 return GIF_ERROR;
281 }
282
283 write_version = EGifGetGifVersion(GifFile);
284
285 /* First write the version prefix into the file. */
286 if (InternalWrite(GifFile, (unsigned char *)write_version,
287 strlen(write_version)) != strlen(write_version)) {
288 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
289 return GIF_ERROR;
290 }
291
292 GifFile->SWidth = Width;
293 GifFile->SHeight = Height;
294 GifFile->SColorResolution = ColorRes;
295 GifFile->SBackGroundColor = BackGround;
296 if (ColorMap) {
297 GifFile->SColorMap = GifMakeMapObject(ColorMap->ColorCount,
298 ColorMap->Colors);
299 if (GifFile->SColorMap == NULL) {
300 GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM;
301 return GIF_ERROR;
302 }
303 } else
304 GifFile->SColorMap = NULL;
305
306 /*
307 * Put the logical screen descriptor into the file:
308 */
309 /* Logical Screen Descriptor: Dimensions */
310 (void)EGifPutWord(Width, GifFile);
311 (void)EGifPutWord(Height, GifFile);
312
313 /* Logical Screen Descriptor: Packed Fields */
314 /* Note: We have actual size of the color table default to the largest
315 * possible size (7+1 == 8 bits) because the decoder can use it to decide
316 * how to display the files.
317 */
318 Buf[0] = (ColorMap ? 0x80 : 0x00) | /* Yes/no global colormap */
319 ((ColorRes - 1) << 4) | /* Bits allocated to each primary color */
320 (ColorMap ? ColorMap->BitsPerPixel - 1 : 0x07 ); /* Actual size of the
321 color table. */
322 if (ColorMap != NULL && ColorMap->SortFlag)
323 Buf[0] |= 0x08;
324 Buf[1] = BackGround; /* Index into the ColorTable for background color */
325 Buf[2] = GifFile->AspectByte; /* Pixel Aspect Ratio */
326 InternalWrite(GifFile, Buf, 3);
327
328 /* If we have Global color map - dump it also: */
329 if (ColorMap != NULL) {
330 int i;
331 for (i = 0; i < ColorMap->ColorCount; i++) {
332 /* Put the ColorMap out also: */
333 Buf[0] = ColorMap->Colors[i].Red;
334 Buf[1] = ColorMap->Colors[i].Green;
335 Buf[2] = ColorMap->Colors[i].Blue;
336 if (InternalWrite(GifFile, Buf, 3) != 3) {
337 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
338 return GIF_ERROR;
339 }
340 }
341 }
342
343 /* Mark this file as has screen descriptor, and no pixel written yet: */
344 Private->FileState |= FILE_STATE_SCREEN;
345
346 return GIF_OK;
347 }
348
349 /******************************************************************************
350 This routine should be called before any attempt to dump an image - any
351 call to any of the pixel dump routines.
352 ******************************************************************************/
353 int
EGifPutImageDesc(GifFileType * GifFile,const int Left,const int Top,const int Width,const int Height,const bool Interlace,const ColorMapObject * ColorMap)354 EGifPutImageDesc(GifFileType *GifFile,
355 const int Left,
356 const int Top,
357 const int Width,
358 const int Height,
359 const bool Interlace,
360 const ColorMapObject *ColorMap)
361 {
362 GifByteType Buf[3];
363 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
364
365 if (Private->FileState & FILE_STATE_IMAGE &&
366 Private->PixelCount > 0xffff0000UL) {
367 /* If already has active image descriptor - something is wrong! */
368 GifFile->Error = E_GIF_ERR_HAS_IMAG_DSCR;
369 return GIF_ERROR;
370 }
371 if (!IS_WRITEABLE(Private)) {
372 /* This file was NOT open for writing: */
373 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
374 return GIF_ERROR;
375 }
376 GifFile->Image.Left = Left;
377 GifFile->Image.Top = Top;
378 GifFile->Image.Width = Width;
379 GifFile->Image.Height = Height;
380 GifFile->Image.Interlace = Interlace;
381 if (ColorMap) {
382 GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
383 ColorMap->Colors);
384 if (GifFile->Image.ColorMap == NULL) {
385 GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM;
386 return GIF_ERROR;
387 }
388 } else {
389 GifFile->Image.ColorMap = NULL;
390 }
391
392 /* Put the image descriptor into the file: */
393 Buf[0] = DESCRIPTOR_INTRODUCER; /* Image separator character. */
394 InternalWrite(GifFile, Buf, 1);
395 (void)EGifPutWord(Left, GifFile);
396 (void)EGifPutWord(Top, GifFile);
397 (void)EGifPutWord(Width, GifFile);
398 (void)EGifPutWord(Height, GifFile);
399 Buf[0] = (ColorMap ? 0x80 : 0x00) |
400 (Interlace ? 0x40 : 0x00) |
401 (ColorMap ? ColorMap->BitsPerPixel - 1 : 0);
402 InternalWrite(GifFile, Buf, 1);
403
404 /* If we have Global color map - dump it also: */
405 if (ColorMap != NULL) {
406 int i;
407 for (i = 0; i < ColorMap->ColorCount; i++) {
408 /* Put the ColorMap out also: */
409 Buf[0] = ColorMap->Colors[i].Red;
410 Buf[1] = ColorMap->Colors[i].Green;
411 Buf[2] = ColorMap->Colors[i].Blue;
412 if (InternalWrite(GifFile, Buf, 3) != 3) {
413 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
414 return GIF_ERROR;
415 }
416 }
417 }
418 if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL) {
419 GifFile->Error = E_GIF_ERR_NO_COLOR_MAP;
420 return GIF_ERROR;
421 }
422
423 /* Mark this file as has screen descriptor: */
424 Private->FileState |= FILE_STATE_IMAGE;
425 Private->PixelCount = (long)Width *(long)Height;
426
427 /* Reset compress algorithm parameters. */
428 (void)EGifSetupCompress(GifFile);
429
430 return GIF_OK;
431 }
432
433 /******************************************************************************
434 Put one full scanned line (Line) of length LineLen into GIF file.
435 ******************************************************************************/
436 int
EGifPutLine(GifFileType * GifFile,GifPixelType * Line,int LineLen)437 EGifPutLine(GifFileType * GifFile, GifPixelType *Line, int LineLen)
438 {
439 int i;
440 GifPixelType Mask;
441 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
442
443 if (!IS_WRITEABLE(Private)) {
444 /* This file was NOT open for writing: */
445 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
446 return GIF_ERROR;
447 }
448
449 if (!LineLen)
450 LineLen = GifFile->Image.Width;
451 if (Private->PixelCount < (unsigned)LineLen) {
452 GifFile->Error = E_GIF_ERR_DATA_TOO_BIG;
453 return GIF_ERROR;
454 }
455 Private->PixelCount -= LineLen;
456
457 /* Make sure the codes are not out of bit range, as we might generate
458 * wrong code (because of overflow when we combine them) in this case: */
459 Mask = CodeMask[Private->BitsPerPixel];
460 for (i = 0; i < LineLen; i++)
461 Line[i] &= Mask;
462
463 return EGifCompressLine(GifFile, Line, LineLen);
464 }
465
466 /******************************************************************************
467 Put one pixel (Pixel) into GIF file.
468 ******************************************************************************/
469 int
EGifPutPixel(GifFileType * GifFile,GifPixelType Pixel)470 EGifPutPixel(GifFileType *GifFile, GifPixelType Pixel)
471 {
472 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
473
474 if (!IS_WRITEABLE(Private)) {
475 /* This file was NOT open for writing: */
476 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
477 return GIF_ERROR;
478 }
479
480 if (Private->PixelCount == 0) {
481 GifFile->Error = E_GIF_ERR_DATA_TOO_BIG;
482 return GIF_ERROR;
483 }
484 --Private->PixelCount;
485
486 /* Make sure the code is not out of bit range, as we might generate
487 * wrong code (because of overflow when we combine them) in this case: */
488 Pixel &= CodeMask[Private->BitsPerPixel];
489
490 return EGifCompressLine(GifFile, &Pixel, 1);
491 }
492
493 /******************************************************************************
494 Put a comment into GIF file using the GIF89 comment extension block.
495 ******************************************************************************/
496 int
EGifPutComment(GifFileType * GifFile,const char * Comment)497 EGifPutComment(GifFileType *GifFile, const char *Comment)
498 {
499 unsigned int length = strlen(Comment);
500 char *buf;
501
502 length = strlen(Comment);
503 if (length <= 255) {
504 return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE,
505 length, Comment);
506 } else {
507 buf = (char *)Comment;
508 if (EGifPutExtensionLeader(GifFile, COMMENT_EXT_FUNC_CODE)
509 == GIF_ERROR) {
510 return GIF_ERROR;
511 }
512
513 /* Break the comment into 255 byte sub blocks */
514 while (length > 255) {
515 if (EGifPutExtensionBlock(GifFile, 255, buf) == GIF_ERROR) {
516 return GIF_ERROR;
517 }
518 buf = buf + 255;
519 length -= 255;
520 }
521 /* Output any partial block and the clear code. */
522 if (length > 0) {
523 if (EGifPutExtensionBlock(GifFile, length, buf) == GIF_ERROR) {
524 return GIF_ERROR;
525 }
526 }
527 if (EGifPutExtensionTrailer(GifFile) == GIF_ERROR) {
528 return GIF_ERROR;
529 }
530 }
531 return GIF_OK;
532 }
533
534 /******************************************************************************
535 Begin an extension block (see GIF manual). More
536 extensions can be dumped using EGifPutExtensionBlock until
537 EGifPutExtensionTrailer is invoked.
538 ******************************************************************************/
539 int
EGifPutExtensionLeader(GifFileType * GifFile,const int ExtCode)540 EGifPutExtensionLeader(GifFileType *GifFile, const int ExtCode)
541 {
542 GifByteType Buf[3];
543 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
544
545 if (!IS_WRITEABLE(Private)) {
546 /* This file was NOT open for writing: */
547 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
548 return GIF_ERROR;
549 }
550
551 Buf[0] = EXTENSION_INTRODUCER;
552 Buf[1] = ExtCode;
553 InternalWrite(GifFile, Buf, 2);
554
555 return GIF_OK;
556 }
557
558 /******************************************************************************
559 Put extension block data (see GIF manual) into a GIF file.
560 ******************************************************************************/
561 int
EGifPutExtensionBlock(GifFileType * GifFile,const int ExtLen,const void * Extension)562 EGifPutExtensionBlock(GifFileType *GifFile,
563 const int ExtLen,
564 const void *Extension)
565 {
566 GifByteType Buf;
567 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
568
569 if (!IS_WRITEABLE(Private)) {
570 /* This file was NOT open for writing: */
571 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
572 return GIF_ERROR;
573 }
574
575 Buf = ExtLen;
576 InternalWrite(GifFile, &Buf, 1);
577 InternalWrite(GifFile, Extension, ExtLen);
578
579 return GIF_OK;
580 }
581
582 /******************************************************************************
583 Put a terminating block (see GIF manual) into a GIF file.
584 ******************************************************************************/
585 int
EGifPutExtensionTrailer(GifFileType * GifFile)586 EGifPutExtensionTrailer(GifFileType *GifFile) {
587
588 GifByteType Buf;
589 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
590
591 if (!IS_WRITEABLE(Private)) {
592 /* This file was NOT open for writing: */
593 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
594 return GIF_ERROR;
595 }
596
597 /* Write the block terminator */
598 Buf = 0;
599 InternalWrite(GifFile, &Buf, 1);
600
601 return GIF_OK;
602 }
603
604 /******************************************************************************
605 Put an extension block (see GIF manual) into a GIF file.
606 Warning: This function is only useful for Extension blocks that have at
607 most one subblock. Extensions with more than one subblock need to use the
608 EGifPutExtension{Leader,Block,Trailer} functions instead.
609 ******************************************************************************/
610 int
EGifPutExtension(GifFileType * GifFile,const int ExtCode,const int ExtLen,const void * Extension)611 EGifPutExtension(GifFileType *GifFile,
612 const int ExtCode,
613 const int ExtLen,
614 const void *Extension) {
615
616 GifByteType Buf[3];
617 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
618
619 if (!IS_WRITEABLE(Private)) {
620 /* This file was NOT open for writing: */
621 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
622 return GIF_ERROR;
623 }
624
625 if (ExtCode == 0)
626 InternalWrite(GifFile, (GifByteType *)&ExtLen, 1);
627 else {
628 Buf[0] = EXTENSION_INTRODUCER;
629 Buf[1] = ExtCode; /* Extension Label */
630 Buf[2] = ExtLen; /* Extension length */
631 InternalWrite(GifFile, Buf, 3);
632 }
633 InternalWrite(GifFile, Extension, ExtLen);
634 Buf[0] = 0;
635 InternalWrite(GifFile, Buf, 1);
636
637 return GIF_OK;
638 }
639
640 /******************************************************************************
641 Render a Graphics Control Block as raw extension data
642 ******************************************************************************/
643
EGifGCBToExtension(const GraphicsControlBlock * GCB,GifByteType * GifExtension)644 size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
645 GifByteType *GifExtension)
646 {
647 GifExtension[0] = 0;
648 GifExtension[0] |= (GCB->TransparentColor == NO_TRANSPARENT_COLOR) ? 0x00 : 0x01;
649 GifExtension[0] |= GCB->UserInputFlag ? 0x02 : 0x00;
650 GifExtension[0] |= ((GCB->DisposalMode & 0x07) << 2);
651 GifExtension[1] = LOBYTE(GCB->DelayTime);
652 GifExtension[2] = HIBYTE(GCB->DelayTime);
653 GifExtension[3] = (char)GCB->TransparentColor;
654 return 4;
655 }
656
657 /******************************************************************************
658 Replace the Graphics Control Block for a saved image, if it exists.
659 ******************************************************************************/
660
EGifGCBToSavedExtension(const GraphicsControlBlock * GCB,GifFileType * GifFile,int ImageIndex)661 int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
662 GifFileType *GifFile, int ImageIndex)
663 {
664 int i;
665 size_t Len;
666 GifByteType buf[sizeof(GraphicsControlBlock)]; /* a bit dodgy... */
667
668 if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1)
669 return GIF_ERROR;
670
671 for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) {
672 ExtensionBlock *ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
673 if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
674 EGifGCBToExtension(GCB, ep->Bytes);
675 return GIF_OK;
676 }
677 }
678
679 Len = EGifGCBToExtension(GCB, (GifByteType *)buf);
680 if (GifAddExtensionBlock(&GifFile->SavedImages[ImageIndex].ExtensionBlockCount,
681 &GifFile->SavedImages[ImageIndex].ExtensionBlocks,
682 GRAPHICS_EXT_FUNC_CODE,
683 Len,
684 (unsigned char *)buf) == GIF_ERROR)
685 return (GIF_ERROR);
686
687 return (GIF_OK);
688 }
689
690 /******************************************************************************
691 Put the image code in compressed form. This routine can be called if the
692 information needed to be piped out as is. Obviously this is much faster
693 than decoding and encoding again. This routine should be followed by calls
694 to EGifPutCodeNext, until NULL block is given.
695 The block should NOT be freed by the user (not dynamically allocated).
696 ******************************************************************************/
697 int
EGifPutCode(GifFileType * GifFile,int CodeSize,const GifByteType * CodeBlock)698 EGifPutCode(GifFileType *GifFile, int CodeSize, const GifByteType *CodeBlock)
699 {
700 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
701
702 if (!IS_WRITEABLE(Private)) {
703 /* This file was NOT open for writing: */
704 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
705 return GIF_ERROR;
706 }
707
708 /* No need to dump code size as Compression set up does any for us: */
709 /*
710 * Buf = CodeSize;
711 * if (InternalWrite(GifFile, &Buf, 1) != 1) {
712 * GifFile->Error = E_GIF_ERR_WRITE_FAILED;
713 * return GIF_ERROR;
714 * }
715 */
716
717 return EGifPutCodeNext(GifFile, CodeBlock);
718 }
719
720 /******************************************************************************
721 Continue to put the image code in compressed form. This routine should be
722 called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If
723 given buffer pointer is NULL, empty block is written to mark end of code.
724 ******************************************************************************/
725 int
EGifPutCodeNext(GifFileType * GifFile,const GifByteType * CodeBlock)726 EGifPutCodeNext(GifFileType *GifFile, const GifByteType *CodeBlock)
727 {
728 GifByteType Buf;
729 GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
730
731 if (CodeBlock != NULL) {
732 if (InternalWrite(GifFile, CodeBlock, CodeBlock[0] + 1)
733 != (unsigned)(CodeBlock[0] + 1)) {
734 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
735 return GIF_ERROR;
736 }
737 } else {
738 Buf = 0;
739 if (InternalWrite(GifFile, &Buf, 1) != 1) {
740 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
741 return GIF_ERROR;
742 }
743 Private->PixelCount = 0; /* And local info. indicate image read. */
744 }
745
746 return GIF_OK;
747 }
748
749 /******************************************************************************
750 This routine should be called last, to close the GIF file.
751 ******************************************************************************/
752 int
EGifCloseFile(GifFileType * GifFile)753 EGifCloseFile(GifFileType *GifFile)
754 {
755 GifByteType Buf;
756 GifFilePrivateType *Private;
757 FILE *File;
758
759 if (GifFile == NULL)
760 return GIF_ERROR;
761
762 Private = (GifFilePrivateType *) GifFile->Private;
763 if (Private == NULL)
764 return GIF_ERROR;
765 if (!IS_WRITEABLE(Private)) {
766 /* This file was NOT open for writing: */
767 GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
768 return GIF_ERROR;
769 }
770
771 File = Private->File;
772
773 Buf = TERMINATOR_INTRODUCER;
774 InternalWrite(GifFile, &Buf, 1);
775
776 if (GifFile->Image.ColorMap) {
777 GifFreeMapObject(GifFile->Image.ColorMap);
778 GifFile->Image.ColorMap = NULL;
779 }
780 if (GifFile->SColorMap) {
781 GifFreeMapObject(GifFile->SColorMap);
782 GifFile->SColorMap = NULL;
783 }
784 if (Private) {
785 if (Private->HashTable) {
786 free((char *) Private->HashTable);
787 }
788 free((char *) Private);
789 }
790
791 if (File && fclose(File) != 0) {
792 GifFile->Error = E_GIF_ERR_CLOSE_FAILED;
793 return GIF_ERROR;
794 }
795
796 /*
797 * Without the #ifndef, we get spurious warnings because Coverity mistakenly
798 * thinks the GIF structure is freed on an error return.
799 */
800 #ifndef __COVERITY__
801 free(GifFile);
802 #endif /* __COVERITY__ */
803
804 return GIF_OK;
805 }
806
807 /******************************************************************************
808 Put 2 bytes (a word) into the given file in little-endian order:
809 ******************************************************************************/
810 static int
EGifPutWord(int Word,GifFileType * GifFile)811 EGifPutWord(int Word, GifFileType *GifFile)
812 {
813 unsigned char c[2];
814
815 c[0] = LOBYTE(Word);
816 c[1] = HIBYTE(Word);
817 if (InternalWrite(GifFile, c, 2) == 2)
818 return GIF_OK;
819 else
820 return GIF_ERROR;
821 }
822
823 /******************************************************************************
824 Setup the LZ compression for this image:
825 ******************************************************************************/
826 static int
EGifSetupCompress(GifFileType * GifFile)827 EGifSetupCompress(GifFileType *GifFile)
828 {
829 int BitsPerPixel;
830 GifByteType Buf;
831 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
832
833 /* Test and see what color map to use, and from it # bits per pixel: */
834 if (GifFile->Image.ColorMap)
835 BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel;
836 else if (GifFile->SColorMap)
837 BitsPerPixel = GifFile->SColorMap->BitsPerPixel;
838 else {
839 GifFile->Error = E_GIF_ERR_NO_COLOR_MAP;
840 return GIF_ERROR;
841 }
842
843 Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
844 InternalWrite(GifFile, &Buf, 1); /* Write the Code size to file. */
845
846 Private->Buf[0] = 0; /* Nothing was output yet. */
847 Private->BitsPerPixel = BitsPerPixel;
848 Private->ClearCode = (1 << BitsPerPixel);
849 Private->EOFCode = Private->ClearCode + 1;
850 Private->RunningCode = Private->EOFCode + 1;
851 Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
852 Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
853 Private->CrntCode = FIRST_CODE; /* Signal that this is first one! */
854 Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
855 Private->CrntShiftDWord = 0;
856
857 /* Clear hash table and send Clear to make sure the decoder do the same. */
858 _ClearHashTable(Private->HashTable);
859
860 if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) {
861 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
862 return GIF_ERROR;
863 }
864 return GIF_OK;
865 }
866
867 /******************************************************************************
868 The LZ compression routine:
869 This version compresses the given buffer Line of length LineLen.
870 This routine can be called a few times (one per scan line, for example), in
871 order to complete the whole image.
872 ******************************************************************************/
873 static int
EGifCompressLine(GifFileType * GifFile,GifPixelType * Line,const int LineLen)874 EGifCompressLine(GifFileType *GifFile,
875 GifPixelType *Line,
876 const int LineLen)
877 {
878 int i = 0, CrntCode, NewCode;
879 unsigned long NewKey;
880 GifPixelType Pixel;
881 GifHashTableType *HashTable;
882 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
883
884 HashTable = Private->HashTable;
885
886 if (Private->CrntCode == FIRST_CODE) /* Its first time! */
887 CrntCode = Line[i++];
888 else
889 CrntCode = Private->CrntCode; /* Get last code in compression. */
890
891 while (i < LineLen) { /* Decode LineLen items. */
892 Pixel = Line[i++]; /* Get next pixel from stream. */
893 /* Form a new unique key to search hash table for the code combines
894 * CrntCode as Prefix string with Pixel as postfix char.
895 */
896 NewKey = (((uint32_t) CrntCode) << 8) + Pixel;
897 if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
898 /* This Key is already there, or the string is old one, so
899 * simple take new code as our CrntCode:
900 */
901 CrntCode = NewCode;
902 } else {
903 /* Put it in hash table, output the prefix code, and make our
904 * CrntCode equal to Pixel.
905 */
906 if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
907 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
908 return GIF_ERROR;
909 }
910 CrntCode = Pixel;
911
912 /* If however the HashTable if full, we send a clear first and
913 * Clear the hash table.
914 */
915 if (Private->RunningCode >= LZ_MAX_CODE) {
916 /* Time to do some clearance: */
917 if (EGifCompressOutput(GifFile, Private->ClearCode)
918 == GIF_ERROR) {
919 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
920 return GIF_ERROR;
921 }
922 Private->RunningCode = Private->EOFCode + 1;
923 Private->RunningBits = Private->BitsPerPixel + 1;
924 Private->MaxCode1 = 1 << Private->RunningBits;
925 _ClearHashTable(HashTable);
926 } else {
927 /* Put this unique key with its relative Code in hash table: */
928 _InsertHashTable(HashTable, NewKey, Private->RunningCode++);
929 }
930 }
931
932 }
933
934 /* Preserve the current state of the compression algorithm: */
935 Private->CrntCode = CrntCode;
936
937 if (Private->PixelCount == 0) {
938 /* We are done - output last Code and flush output buffers: */
939 if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
940 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
941 return GIF_ERROR;
942 }
943 if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) {
944 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
945 return GIF_ERROR;
946 }
947 if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) {
948 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
949 return GIF_ERROR;
950 }
951 }
952
953 return GIF_OK;
954 }
955
956 /******************************************************************************
957 The LZ compression output routine:
958 This routine is responsible for the compression of the bit stream into
959 8 bits (bytes) packets.
960 Returns GIF_OK if written successfully.
961 ******************************************************************************/
962 static int
EGifCompressOutput(GifFileType * GifFile,const int Code)963 EGifCompressOutput(GifFileType *GifFile,
964 const int Code)
965 {
966 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
967 int retval = GIF_OK;
968
969 if (Code == FLUSH_OUTPUT) {
970 while (Private->CrntShiftState > 0) {
971 /* Get Rid of what is left in DWord, and flush it. */
972 if (EGifBufferedOutput(GifFile, Private->Buf,
973 Private->CrntShiftDWord & 0xff) == GIF_ERROR)
974 retval = GIF_ERROR;
975 Private->CrntShiftDWord >>= 8;
976 Private->CrntShiftState -= 8;
977 }
978 Private->CrntShiftState = 0; /* For next time. */
979 if (EGifBufferedOutput(GifFile, Private->Buf,
980 FLUSH_OUTPUT) == GIF_ERROR)
981 retval = GIF_ERROR;
982 } else {
983 Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState;
984 Private->CrntShiftState += Private->RunningBits;
985 while (Private->CrntShiftState >= 8) {
986 /* Dump out full bytes: */
987 if (EGifBufferedOutput(GifFile, Private->Buf,
988 Private->CrntShiftDWord & 0xff) == GIF_ERROR)
989 retval = GIF_ERROR;
990 Private->CrntShiftDWord >>= 8;
991 Private->CrntShiftState -= 8;
992 }
993 }
994
995 /* If code cannt fit into RunningBits bits, must raise its size. Note */
996 /* however that codes above 4095 are used for special signaling. */
997 if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {
998 Private->MaxCode1 = 1 << ++Private->RunningBits;
999 }
1000
1001 return retval;
1002 }
1003
1004 /******************************************************************************
1005 This routines buffers the given characters until 255 characters are ready
1006 to be output. If Code is equal to -1 the buffer is flushed (EOF).
1007 The buffer is Dumped with first byte as its size, as GIF format requires.
1008 Returns GIF_OK if written successfully.
1009 ******************************************************************************/
1010 static int
EGifBufferedOutput(GifFileType * GifFile,GifByteType * Buf,int c)1011 EGifBufferedOutput(GifFileType *GifFile,
1012 GifByteType *Buf,
1013 int c)
1014 {
1015 if (c == FLUSH_OUTPUT) {
1016 /* Flush everything out. */
1017 if (Buf[0] != 0
1018 && InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
1019 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
1020 return GIF_ERROR;
1021 }
1022 /* Mark end of compressed data, by an empty block (see GIF doc): */
1023 Buf[0] = 0;
1024 if (InternalWrite(GifFile, Buf, 1) != 1) {
1025 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
1026 return GIF_ERROR;
1027 }
1028 } else {
1029 if (Buf[0] == 255) {
1030 /* Dump out this buffer - it is full: */
1031 if (InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
1032 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
1033 return GIF_ERROR;
1034 }
1035 Buf[0] = 0;
1036 }
1037 Buf[++Buf[0]] = c;
1038 }
1039
1040 return GIF_OK;
1041 }
1042
1043 /******************************************************************************
1044 This routine writes to disk an in-core representation of a GIF previously
1045 created by DGifSlurp().
1046 ******************************************************************************/
1047
1048 static int
EGifWriteExtensions(GifFileType * GifFileOut,ExtensionBlock * ExtensionBlocks,int ExtensionBlockCount)1049 EGifWriteExtensions(GifFileType *GifFileOut,
1050 ExtensionBlock *ExtensionBlocks,
1051 int ExtensionBlockCount)
1052 {
1053 if (ExtensionBlocks) {
1054 ExtensionBlock *ep;
1055 int j;
1056
1057 for (j = 0; j < ExtensionBlockCount; j++) {
1058 ep = &ExtensionBlocks[j];
1059 if (ep->Function != CONTINUE_EXT_FUNC_CODE)
1060 if (EGifPutExtensionLeader(GifFileOut, ep->Function) == GIF_ERROR)
1061 return (GIF_ERROR);
1062 if (EGifPutExtensionBlock(GifFileOut, ep->ByteCount, ep->Bytes) == GIF_ERROR)
1063 return (GIF_ERROR);
1064 if (j == ExtensionBlockCount - 1 || (ep+1)->Function != CONTINUE_EXT_FUNC_CODE)
1065 if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
1066 return (GIF_ERROR);
1067 }
1068 }
1069
1070 return (GIF_OK);
1071 }
1072
1073 int
EGifSpew(GifFileType * GifFileOut)1074 EGifSpew(GifFileType *GifFileOut)
1075 {
1076 int i, j;
1077
1078 if (EGifPutScreenDesc(GifFileOut,
1079 GifFileOut->SWidth,
1080 GifFileOut->SHeight,
1081 GifFileOut->SColorResolution,
1082 GifFileOut->SBackGroundColor,
1083 GifFileOut->SColorMap) == GIF_ERROR) {
1084 return (GIF_ERROR);
1085 }
1086
1087 for (i = 0; i < GifFileOut->ImageCount; i++) {
1088 SavedImage *sp = &GifFileOut->SavedImages[i];
1089 int SavedHeight = sp->ImageDesc.Height;
1090 int SavedWidth = sp->ImageDesc.Width;
1091
1092 /* this allows us to delete images by nuking their rasters */
1093 if (sp->RasterBits == NULL)
1094 continue;
1095
1096 if (EGifWriteExtensions(GifFileOut,
1097 sp->ExtensionBlocks,
1098 sp->ExtensionBlockCount) == GIF_ERROR)
1099 return (GIF_ERROR);
1100
1101 if (EGifPutImageDesc(GifFileOut,
1102 sp->ImageDesc.Left,
1103 sp->ImageDesc.Top,
1104 SavedWidth,
1105 SavedHeight,
1106 sp->ImageDesc.Interlace,
1107 sp->ImageDesc.ColorMap) == GIF_ERROR)
1108 return (GIF_ERROR);
1109
1110 if (sp->ImageDesc.Interlace) {
1111 /*
1112 * The way an interlaced image should be written -
1113 * offsets and jumps...
1114 */
1115 int InterlacedOffset[] = { 0, 4, 2, 1 };
1116 int InterlacedJumps[] = { 8, 8, 4, 2 };
1117 int k;
1118 /* Need to perform 4 passes on the images: */
1119 for (k = 0; k < 4; k++)
1120 for (j = InterlacedOffset[k];
1121 j < SavedHeight;
1122 j += InterlacedJumps[k]) {
1123 if (EGifPutLine(GifFileOut,
1124 sp->RasterBits + j * SavedWidth,
1125 SavedWidth) == GIF_ERROR)
1126 return (GIF_ERROR);
1127 }
1128 } else {
1129 for (j = 0; j < SavedHeight; j++) {
1130 if (EGifPutLine(GifFileOut,
1131 sp->RasterBits + j * SavedWidth,
1132 SavedWidth) == GIF_ERROR)
1133 return (GIF_ERROR);
1134 }
1135 }
1136 }
1137
1138 if (EGifWriteExtensions(GifFileOut,
1139 GifFileOut->ExtensionBlocks,
1140 GifFileOut->ExtensionBlockCount) == GIF_ERROR)
1141 return (GIF_ERROR);
1142
1143 if (EGifCloseFile(GifFileOut) == GIF_ERROR)
1144 return (GIF_ERROR);
1145
1146 return (GIF_OK);
1147 }
1148
1149 /* end */
1150