• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.2
/frmts/gif/gifdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GIF Driver
4
 * Purpose:  Implement GDAL GIF Support using libungif code.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2001, Frank Warmerdam
9
 * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "gifabstractdataset.h"
15

16
#include "cpl_string.h"
17
#include "gdal_frmts.h"
18
#include "gdal_pam.h"
19
#include "gifdrivercore.h"
20

21
CPL_C_START
22
#if !(defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5)
23

24
// This prototype seems to have been messed up!
25
GifFileType *EGifOpen(void *userData, OutputFunc writeFunc);
26

27
// Define alias compatible with giflib >= 5.0.0
28
#define GifMakeMapObject MakeMapObject
29
#define GifFreeMapObject FreeMapObject
30

31
#endif  // defined(GIFLIB_MAJOR) && GIFLIB_MAJOR < 5
32

33
CPL_C_END
34

35
/************************************************************************/
36
/*                          VSIGIFWriteFunc()                           */
37
/*                                                                      */
38
/*      Proxy write function.                                           */
39
/************************************************************************/
40

41
static int VSIGIFWriteFunc(GifFileType *psGFile, const GifByteType *pabyBuffer,
1,414✔
42
                           int nBytesToWrite)
43

44
{
45
    VSILFILE *fp = static_cast<VSILFILE *>(psGFile->UserData);
1,414✔
46
    if (VSIFTellL(fp) == 0 && nBytesToWrite >= 6 &&
1,420✔
47
        memcmp(pabyBuffer, "GIF87a", 6) == 0)
6✔
48
    {
49
        // This is a hack to write a GIF89a instead of GIF87a (we have to, since
50
        // we are using graphical extension block).  EGifSpew would write GIF89a
51
        // when it detects an extension block if we were using it As we don't,
52
        // we could have used EGifSetGifVersion instead, but the version of
53
        // libungif in GDAL has a bug: it writes on read-only memory!
54
        // This is a well-known problem. Just google for "EGifSetGifVersion
55
        // segfault".
56
        // Most readers don't even care if it is GIF87a or GIF89a, but it is
57
        // better to write the right version.
58

59
        size_t nRet = VSIFWriteL("GIF89a", 1, 6, fp);
6✔
60
        nRet += VSIFWriteL(reinterpret_cast<const char *>(pabyBuffer) + 6, 1,
12✔
61
                           nBytesToWrite - 6, fp);
6✔
62
        return static_cast<int>(nRet);
6✔
63
    }
64

65
    return static_cast<int>(VSIFWriteL(pabyBuffer, 1, nBytesToWrite, fp));
1,408✔
66
}
67

68
/************************************************************************/
69
/* ==================================================================== */
70
/*                                  GIFDataset                          */
71
/* ==================================================================== */
72
/************************************************************************/
73

74
class GIFRasterBand;
75

76
class GIFDataset final : public GIFAbstractDataset
60✔
77
{
78
    friend class GIFRasterBand;
79

80
  public:
81
    GIFDataset();
82
    ~GIFDataset() override;
83

84
    static GDALDataset *Open(GDALOpenInfo *);
85

86
    static GDALDataset *CreateCopy(const char *pszFilename,
87
                                   GDALDataset *poSrcDS, int bStrict,
88
                                   char **papszOptions,
89
                                   GDALProgressFunc pfnProgress,
90
                                   void *pProgressData);
91
};
92

93
GIFDataset::~GIFDataset() = default;
94

95
/************************************************************************/
96
/* ==================================================================== */
97
/*                            GIFRasterBand                             */
98
/* ==================================================================== */
99
/************************************************************************/
100

101
class GIFRasterBand final : public GIFAbstractRasterBand
102
{
103
  public:
104
    GIFRasterBand(GIFDataset *, int, SavedImage *, int);
105
    CPLErr IReadBlock(int, int, void *) override;
106
};
107

108
/************************************************************************/
109
/*                           GIFRasterBand()                            */
110
/************************************************************************/
111

112
GIFRasterBand::GIFRasterBand(GIFDataset *poDSIn, int nBandIn,
30✔
113
                             SavedImage *psSavedImage, int nBackground)
30✔
114
    : GIFAbstractRasterBand(poDSIn, nBandIn, psSavedImage, nBackground, FALSE)
30✔
115
{
116
}
30✔
117

118
/************************************************************************/
119
/*                             IReadBlock()                             */
120
/************************************************************************/
121

122
CPLErr GIFRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
2,960✔
123
                                 void *pImage)
124
{
125
    CPLAssert(nBlockXOff == 0);
2,960✔
126

127
    if (psImage == nullptr)
2,960✔
128
    {
129
        memset(pImage, 0, nBlockXSize);
20✔
130
        return CE_None;
20✔
131
    }
132

133
    if (panInterlaceMap != nullptr)
2,940✔
134
        nBlockYOff = panInterlaceMap[nBlockYOff];
×
135

136
    memcpy(pImage, psImage->RasterBits + nBlockYOff * nBlockXSize, nBlockXSize);
2,940✔
137

138
    return CE_None;
2,940✔
139
}
140

141
/************************************************************************/
142
/* ==================================================================== */
143
/*                             GIFDataset                               */
144
/* ==================================================================== */
145
/************************************************************************/
146

147
/************************************************************************/
148
/*                            GIFDataset()                            */
149
/************************************************************************/
150

151
GIFDataset::GIFDataset()
30✔
152
{
153
}
30✔
154

155
/************************************************************************/
156
/*                                Open()                                */
157
/************************************************************************/
158

159
GDALDataset *GIFDataset::Open(GDALOpenInfo *poOpenInfo)
31✔
160

161
{
162
    if (!GIFDriverIdentify(poOpenInfo))
31✔
163
        return nullptr;
×
164

165
    if (poOpenInfo->eAccess == GA_Update)
31✔
166
    {
167
        ReportUpdateNotSupportedByDriver("GIF");
×
168
        return nullptr;
×
169
    }
170

171
    /* -------------------------------------------------------------------- */
172
    /*      Ingest.                                                         */
173
    /* -------------------------------------------------------------------- */
174
    VSILFILE *fp = poOpenInfo->fpL;
31✔
175
    poOpenInfo->fpL = nullptr;
31✔
176

177
    GifFileType *hGifFile =
178
        GIFAbstractDataset::myDGifOpen(fp, GIFAbstractDataset::ReadFunc);
31✔
179
    if (hGifFile == nullptr)
31✔
180
    {
181
        VSIFCloseL(fp);
×
182
        CPLError(CE_Failure, CPLE_OpenFailed,
×
183
                 "DGifOpen() failed for %s.  "
184
                 "Perhaps the gif file is corrupt?",
185
                 poOpenInfo->pszFilename);
186

187
        return nullptr;
×
188
    }
189

190
    // The following code enables us to detect GIF datasets eligible
191
    // for BIGGIF driver even with an unpatched giflib.
192

193
    /* -------------------------------------------------------------------- */
194
    /*      Find the first image record.                                    */
195
    /* -------------------------------------------------------------------- */
196
    GifRecordType RecordType = FindFirstImage(hGifFile);
31✔
197
    if (RecordType == IMAGE_DESC_RECORD_TYPE &&
62✔
198
        DGifGetImageDesc(hGifFile) != GIF_ERROR)
31✔
199
    {
200
        const int width = hGifFile->SavedImages[0].ImageDesc.Width;
31✔
201
        const int height = hGifFile->SavedImages[0].ImageDesc.Height;
31✔
202
        if (static_cast<double>(width) * height > 100000000.0)
31✔
203
        {
204
            CPLDebug("GIF", "Due to limitations of the GDAL GIF driver we "
2✔
205
                            "deliberately avoid opening large GIF files "
206
                            "(larger than 100 megapixels).");
207
            GIFAbstractDataset::myDGifCloseFile(hGifFile);
2✔
208
            // Reset poOpenInfo->fpL since BIGGIF may need it.
209
            poOpenInfo->fpL = fp;
2✔
210
            VSIFSeekL(fp, 0, SEEK_SET);
2✔
211
            return nullptr;
2✔
212
        }
213
    }
214

215
    GIFAbstractDataset::myDGifCloseFile(hGifFile);
29✔
216

217
    VSIFSeekL(fp, 0, SEEK_SET);
29✔
218

219
    hGifFile = GIFAbstractDataset::myDGifOpen(fp, GIFAbstractDataset::ReadFunc);
29✔
220
    if (hGifFile == nullptr)
29✔
221
    {
222
        VSIFCloseL(fp);
×
223
        CPLError(CE_Failure, CPLE_OpenFailed,
×
224
                 "DGifOpen() failed for %s.  "
225
                 "Perhaps the gif file is corrupt?",
226
                 poOpenInfo->pszFilename);
227

228
        return nullptr;
×
229
    }
230

231
    const int nGifErr = DGifSlurp(hGifFile);
29✔
232

233
    if (nGifErr != GIF_OK || hGifFile->SavedImages == nullptr)
29✔
234
    {
235
        VSIFCloseL(fp);
×
236
        GIFAbstractDataset::myDGifCloseFile(hGifFile);
×
237

238
        if (nGifErr == D_GIF_ERR_DATA_TOO_BIG)
×
239
        {
240
            CPLDebug("GIF",
×
241
                     "DGifSlurp() failed for %s because it was too large.  "
242
                     "Due to limitations of the GDAL GIF driver we "
243
                     "deliberately avoid opening large GIF files "
244
                     "(larger than 100 megapixels).",
245
                     poOpenInfo->pszFilename);
246
            return nullptr;
×
247
        }
248

249
        CPLError(CE_Failure, CPLE_OpenFailed,
×
250
                 "DGifSlurp() failed for %s.  "
251
                 "Perhaps the gif file is corrupt?",
252
                 poOpenInfo->pszFilename);
253

254
        return nullptr;
×
255
    }
256

257
    /* -------------------------------------------------------------------- */
258
    /*      Create a corresponding GDALDataset.                             */
259
    /* -------------------------------------------------------------------- */
260
    GIFDataset *poDS = new GIFDataset();
29✔
261

262
    poDS->fp = fp;
29✔
263
    poDS->eAccess = GA_ReadOnly;
29✔
264
    poDS->hGifFile = hGifFile;
29✔
265

266
    /* -------------------------------------------------------------------- */
267
    /*      Capture some information from the file that is of interest.     */
268
    /* -------------------------------------------------------------------- */
269
    poDS->nRasterXSize = hGifFile->SavedImages[0].ImageDesc.Width;
29✔
270
    poDS->nRasterYSize = hGifFile->SavedImages[0].ImageDesc.Height;
29✔
271
    if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
29✔
272
    {
273
        delete poDS;
×
274
        return nullptr;
×
275
    }
276

277
    /* -------------------------------------------------------------------- */
278
    /*      Create band information objects.                                */
279
    /* -------------------------------------------------------------------- */
280
    for (int iImage = 0; iImage < hGifFile->ImageCount; iImage++)
58✔
281
    {
282
        SavedImage *psImage = hGifFile->SavedImages + iImage;
29✔
283

284
        if (psImage->ImageDesc.Width != poDS->nRasterXSize ||
29✔
285
            psImage->ImageDesc.Height != poDS->nRasterYSize)
29✔
286
            continue;
×
287

288
        if (psImage->ImageDesc.ColorMap == nullptr &&
29✔
289
            poDS->hGifFile->SColorMap == nullptr)
29✔
290
        {
291
            CPLDebug("GIF", "Skipping image without color table");
×
292
            continue;
×
293
        }
294
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
295
        // Since giflib 5, de-interlacing is done by DGifSlurp().
296
        psImage->ImageDesc.Interlace = false;
29✔
297
#endif
298
        poDS->SetBand(poDS->nBands + 1,
29✔
299
                      new GIFRasterBand(poDS, poDS->nBands + 1, psImage,
29✔
300
                                        hGifFile->SBackGroundColor));
29✔
301
    }
302
    if (poDS->nBands == 0)
29✔
303
    {
304
        delete poDS;
×
305
        return nullptr;
×
306
    }
307

308
    /* -------------------------------------------------------------------- */
309
    /*      Check for georeferencing.                                       */
310
    /* -------------------------------------------------------------------- */
311
    poDS->DetectGeoreferencing(poOpenInfo);
29✔
312

313
    /* -------------------------------------------------------------------- */
314
    /*      Initialize any PAM information.                                 */
315
    /* -------------------------------------------------------------------- */
316
    poDS->SetDescription(poOpenInfo->pszFilename);
29✔
317
    poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
29✔
318

319
    /* -------------------------------------------------------------------- */
320
    /*      Support overviews.                                              */
321
    /* -------------------------------------------------------------------- */
322
    poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
58✔
323
                                poOpenInfo->GetSiblingFiles());
29✔
324

325
    return poDS;
29✔
326
}
327

328
/************************************************************************/
329
/*                        GDALPrintGifError()                           */
330
/************************************************************************/
331

332
static void GDALPrintGifError(CPL_UNUSED GifFileType *hGifFile,
×
333
                              const char *pszMsg)
334
{
335
    // GIFLIB_MAJOR is only defined in libgif >= 4.2.0.
336
    // libgif 4.2.0 has retired PrintGifError() and added GifErrorString().
337
#if defined(GIFLIB_MAJOR) && defined(GIFLIB_MINOR) &&                          \
338
    ((GIFLIB_MAJOR == 4 && GIFLIB_MINOR >= 2) || GIFLIB_MAJOR > 4)
339
    // Static string actually, hence the const char* cast.
340

341
#if GIFLIB_MAJOR >= 5
342
    const char *pszGIFLIBError = GifErrorString(hGifFile->Error);
×
343
#else
344
    // TODO(schwehr): Can we remove the cast for older libgif?
345
    const char *pszGIFLIBError = (const char *)GifErrorString();
346
#endif
347
    if (pszGIFLIBError == nullptr)
×
348
        pszGIFLIBError = "Unknown error";
×
349
    CPLError(CE_Failure, CPLE_AppDefined, "%s. GIFLib Error : %s", pszMsg,
×
350
             pszGIFLIBError);
351
#else
352
    PrintGifError();
353
    CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMsg);
354
#endif
355
}
×
356

357
/************************************************************************/
358
/*                             CreateCopy()                             */
359
/************************************************************************/
360

361
GDALDataset *GIFDataset::CreateCopy(const char *pszFilename,
24✔
362
                                    GDALDataset *poSrcDS, int bStrict,
363
                                    char **papszOptions,
364
                                    GDALProgressFunc pfnProgress,
365
                                    void *pProgressData)
366

367
{
368
    /* -------------------------------------------------------------------- */
369
    /*      Check for interlaced option.                                    */
370
    /* -------------------------------------------------------------------- */
371
    const bool bInterlace = CPLFetchBool(papszOptions, "INTERLACING", false);
24✔
372

373
    /* -------------------------------------------------------------------- */
374
    /*      Some some rudimentary checks                                    */
375
    /* -------------------------------------------------------------------- */
376
    const int nBands = poSrcDS->GetRasterCount();
24✔
377
    if (nBands != 1)
24✔
378
    {
379
        CPLError(CE_Failure, CPLE_NotSupported,
5✔
380
                 "GIF driver only supports one band images.");
381

382
        return nullptr;
5✔
383
    }
384

385
    const int nXSize = poSrcDS->GetRasterXSize();
19✔
386
    const int nYSize = poSrcDS->GetRasterYSize();
19✔
387
    if (nXSize > 65535 || nYSize > 65535)
19✔
388
    {
389
        CPLError(CE_Failure, CPLE_NotSupported,
×
390
                 "GIF driver only supports datasets up to 65535x65535 size.");
391

392
        return nullptr;
×
393
    }
394

395
    if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte && bStrict)
19✔
396
    {
397
        CPLError(CE_Failure, CPLE_NotSupported,
10✔
398
                 "GIF driver doesn't support data type %s. "
399
                 "Only eight bit bands supported.",
400
                 GDALGetDataTypeName(
401
                     poSrcDS->GetRasterBand(1)->GetRasterDataType()));
402

403
        return nullptr;
10✔
404
    }
405

406
    /* -------------------------------------------------------------------- */
407
    /*      Open the output file.                                           */
408
    /* -------------------------------------------------------------------- */
409
    VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
9✔
410
    if (fp == nullptr)
9✔
411
    {
412
        CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
3✔
413
                 pszFilename, VSIStrerror(errno));
3✔
414
        return nullptr;
3✔
415
    }
416

417
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
418
    int nError = 0;
6✔
419
    GifFileType *hGifFile = EGifOpen(fp, VSIGIFWriteFunc, &nError);
6✔
420
#else
421
    GifFileType *hGifFile = EGifOpen(fp, VSIGIFWriteFunc);
422
#endif
423
    if (hGifFile == nullptr)
6✔
424
    {
425
        VSIFCloseL(fp);
×
426
        CPLError(CE_Failure, CPLE_OpenFailed,
×
427
                 "EGifOpenFilename(%s) failed.  Does file already exist?",
428
                 pszFilename);
429

430
        return nullptr;
×
431
    }
432

433
    /* -------------------------------------------------------------------- */
434
    /*      Prepare colortable.                                             */
435
    /* -------------------------------------------------------------------- */
436
    GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
6✔
437
    ColorMapObject *psGifCT = nullptr;
6✔
438

439
    if (poBand->GetColorTable() == nullptr)
6✔
440
    {
441
        psGifCT = GifMakeMapObject(256, nullptr);
5✔
442
        if (psGifCT == nullptr)
5✔
443
        {
444
            CPLError(CE_Failure, CPLE_AppDefined,
×
445
                     "Cannot allocate color table");
446
            GIFAbstractDataset::myEGifCloseFile(hGifFile);
×
447
            VSIFCloseL(fp);
×
448
            return nullptr;
×
449
        }
450
        for (int iColor = 0; iColor < 256; iColor++)
1,285✔
451
        {
452
            psGifCT->Colors[iColor].Red = static_cast<GifByteType>(iColor);
1,280✔
453
            psGifCT->Colors[iColor].Green = static_cast<GifByteType>(iColor);
1,280✔
454
            psGifCT->Colors[iColor].Blue = static_cast<GifByteType>(iColor);
1,280✔
455
        }
456
    }
457
    else
458
    {
459
        GDALColorTable *poCT = poBand->GetColorTable();
1✔
460
        int nFullCount = 2;
1✔
461

462
        while (nFullCount < poCT->GetColorEntryCount())
4✔
463
            nFullCount = nFullCount * 2;
3✔
464

465
        psGifCT = GifMakeMapObject(nFullCount, nullptr);
1✔
466
        if (psGifCT == nullptr)
1✔
467
        {
468
            CPLError(CE_Failure, CPLE_AppDefined,
×
469
                     "Cannot allocate color table");
470
            GIFAbstractDataset::myEGifCloseFile(hGifFile);
×
471
            VSIFCloseL(fp);
×
472
            return nullptr;
×
473
        }
474
        int iColor = 0;
1✔
475
        for (; iColor < poCT->GetColorEntryCount(); iColor++)
17✔
476
        {
477
            GDALColorEntry sEntry;
478

479
            poCT->GetColorEntryAsRGB(iColor, &sEntry);
16✔
480
            psGifCT->Colors[iColor].Red = static_cast<GifByteType>(sEntry.c1);
16✔
481
            psGifCT->Colors[iColor].Green = static_cast<GifByteType>(sEntry.c2);
16✔
482
            psGifCT->Colors[iColor].Blue = static_cast<GifByteType>(sEntry.c3);
16✔
483
        }
484
        for (; iColor < nFullCount; iColor++)
1✔
485
        {
486
            psGifCT->Colors[iColor].Red = 0;
×
487
            psGifCT->Colors[iColor].Green = 0;
×
488
            psGifCT->Colors[iColor].Blue = 0;
×
489
        }
490
    }
491

492
    /* -------------------------------------------------------------------- */
493
    /*      Setup parameters.                                               */
494
    /* -------------------------------------------------------------------- */
495
    if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 8, /* ColorRes */
6✔
496
                          255,                         /* Background */
497
                          psGifCT) == GIF_ERROR)
6✔
498
    {
499
        GifFreeMapObject(psGifCT);
×
500
        GDALPrintGifError(hGifFile, "Error writing gif file.");
×
501
        GIFAbstractDataset::myEGifCloseFile(hGifFile);
×
502
        VSIFCloseL(fp);
×
503
        return nullptr;
×
504
    }
505

506
    GifFreeMapObject(psGifCT);
6✔
507
    psGifCT = nullptr;
6✔
508

509
    // Support for transparency.
510
    int bNoDataValue = 0;
6✔
511
    double noDataValue = poBand->GetNoDataValue(&bNoDataValue);
6✔
512
    if (bNoDataValue && noDataValue >= 0 && noDataValue <= 255)
6✔
513
    {
514
        unsigned char extensionData[4] = {
1✔
515
            1,  // Transparent Color Flag.
516
            0, 0, static_cast<unsigned char>(noDataValue)};
1✔
517
        EGifPutExtension(hGifFile, 0xf9, 4, extensionData);
1✔
518
    }
519

520
    if (EGifPutImageDesc(hGifFile, 0, 0, nXSize, nYSize, bInterlace, nullptr) ==
6✔
521
        GIF_ERROR)
522
    {
523
        GDALPrintGifError(hGifFile, "Error writing gif file.");
×
524
        GIFAbstractDataset::myEGifCloseFile(hGifFile);
×
525
        VSIFCloseL(fp);
×
526
        return nullptr;
×
527
    }
528

529
    /* -------------------------------------------------------------------- */
530
    /*      Loop over image, copying image data.                            */
531
    /* -------------------------------------------------------------------- */
532
    GDALPamDataset *poDS = nullptr;
6✔
533
    GByte *pabyScanline = static_cast<GByte *>(CPLMalloc(nXSize));
6✔
534

535
    if (!pfnProgress(0.0, nullptr, pProgressData))
6✔
536
    {
537
        CPLError(CE_Failure, CPLE_AppDefined, "Unable to setup progress.");
×
538
    }
539

540
    if (!bInterlace)
6✔
541
    {
542
        for (int iLine = 0; iLine < nYSize; iLine++)
475✔
543
        {
544
            const CPLErr eErr = poBand->RasterIO(
940✔
545
                GF_Read, 0, iLine, nXSize, 1, pabyScanline, nXSize, 1, GDT_Byte,
546
                nBands, static_cast<GSpacing>(nBands) * nXSize, nullptr);
470✔
547

548
            if (eErr != CE_None ||
940✔
549
                EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
470✔
550
            {
551
                CPLError(CE_Failure, CPLE_AppDefined,
×
552
                         "Error writing gif file.");
553
                goto error;
×
554
            }
555

556
            if (!pfnProgress((iLine + 1) * 1.0 / nYSize, nullptr,
470✔
557
                             pProgressData))
558
            {
559
                goto error;
×
560
            }
561
        }
562
    }
563
    else
564
    {
565
        int nLinesRead = 0;
1✔
566
        // Need to perform 4 passes on the images:
567
        for (int i = 0; i < 4; i++)
5✔
568
        {
569
            for (int j = InterlacedOffset[i]; j < nYSize;
24✔
570
                 j += InterlacedJumps[i])
20✔
571
            {
572
                const CPLErr eErr =
573
                    poBand->RasterIO(GF_Read, 0, j, nXSize, 1, pabyScanline,
20✔
574
                                     nXSize, 1, GDT_Byte, 1, nXSize, nullptr);
575

576
                if (eErr != CE_None ||
40✔
577
                    EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
20✔
578
                {
579
                    CPLError(CE_Failure, CPLE_AppDefined,
×
580
                             "Error writing gif file.");
581
                    goto error;
×
582
                }
583

584
                nLinesRead++;
20✔
585
                if (!pfnProgress(nLinesRead * 1.0 / nYSize, nullptr,
20✔
586
                                 pProgressData))
587
                {
588
                    goto error;
×
589
                }
590
            }
591
        }
592
    }
593

594
    CPLFree(pabyScanline);
6✔
595
    pabyScanline = nullptr;
6✔
596

597
    /* -------------------------------------------------------------------- */
598
    /*      cleanup                                                         */
599
    /* -------------------------------------------------------------------- */
600
    if (GIFAbstractDataset::myEGifCloseFile(hGifFile) == GIF_ERROR)
6✔
601
    {
602
        CPLError(CE_Failure, CPLE_AppDefined, "EGifCloseFile() failed.");
×
603
        hGifFile = nullptr;
×
604
        goto error;
×
605
    }
606
    hGifFile = nullptr;
6✔
607

608
    VSIFCloseL(fp);
6✔
609
    fp = nullptr;
6✔
610

611
    /* -------------------------------------------------------------------- */
612
    /*      Do we need a world file?                                        */
613
    /* -------------------------------------------------------------------- */
614
    if (CPLFetchBool(papszOptions, "WORLDFILE", false))
6✔
615
    {
616
        GDALGeoTransform gt;
×
617
        if (poSrcDS->GetGeoTransform(gt) == CE_None)
×
618
            GDALWriteWorldFile(pszFilename, "wld", gt.data());
×
619
    }
620

621
    /* -------------------------------------------------------------------- */
622
    /*      Re-open dataset, and copy any auxiliary pam information.         */
623
    /* -------------------------------------------------------------------- */
624

625
    // If writing to stdout, we can't reopen it, so return
626
    // a fake dataset to make the caller happy.
627
    CPLPushErrorHandler(CPLQuietErrorHandler);
6✔
628
    poDS = static_cast<GDALPamDataset *>(GDALOpen(pszFilename, GA_ReadOnly));
6✔
629
    CPLPopErrorHandler();
6✔
630
    if (poDS)
6✔
631
    {
632
        poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
5✔
633
        return poDS;
5✔
634
    }
635
    else
636
    {
637
        CPLErrorReset();
1✔
638

639
        GIFDataset *poGIF_DS = new GIFDataset();
1✔
640
        poGIF_DS->nRasterXSize = nXSize;
1✔
641
        poGIF_DS->nRasterYSize = nYSize;
1✔
642
        for (int i = 0; i < nBands; i++)
2✔
643
            poGIF_DS->SetBand(i + 1,
1✔
644
                              new GIFRasterBand(poGIF_DS, i + 1, nullptr, 0));
1✔
645
        return poGIF_DS;
1✔
646
    }
647

648
error:
×
649
    if (hGifFile)
×
650
        GIFAbstractDataset::myEGifCloseFile(hGifFile);
×
651
    if (fp)
×
652
        VSIFCloseL(fp);
×
653
    if (pabyScanline)
×
654
        CPLFree(pabyScanline);
×
655
    return nullptr;
×
656
}
657

658
/************************************************************************/
659
/*                          GDALRegister_GIF()                          */
660
/************************************************************************/
661

662
void GDALRegister_GIF()
19✔
663

664
{
665
    if (GDALGetDriverByName(GIF_DRIVER_NAME) != nullptr)
19✔
666
        return;
×
667

668
    GDALDriver *poDriver = new GDALDriver();
19✔
669

670
    GIFDriverSetCommonMetadata(poDriver);
19✔
671
    poDriver->pfnOpen = GIFDataset::Open;
19✔
672
    poDriver->pfnCreateCopy = GIFDataset::CreateCopy;
19✔
673

674
    GetGDALDriverManager()->RegisterDriver(poDriver);
19✔
675

676
#ifdef GIF_PLUGIN
677
    GDALRegister_BIGGIF();
19✔
678
#endif
679
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc