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