Coverage Report

Created: 2023-12-08 06:35

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