• 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

88.21
/frmts/gif/gifabstractdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GIF Driver
4
 * Purpose:  GIF Abstract Dataset
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ****************************************************************************
8
 * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "gifabstractdataset.h"
14

15
/************************************************************************/
16
/* ==================================================================== */
17
/*                         GIFAbstractDataset                           */
18
/* ==================================================================== */
19
/************************************************************************/
20

21
/************************************************************************/
22
/*                         GIFAbstractDataset()                         */
23
/************************************************************************/
24

25
GIFAbstractDataset::GIFAbstractDataset()
36✔
26
    : fp(nullptr), hGifFile(nullptr), bGeoTransformValid(FALSE), nGCPCount(0),
27
      pasGCPList(nullptr), bHasReadXMPMetadata(FALSE)
36✔
28
{
29
}
36✔
30

31
/************************************************************************/
32
/*                        ~GIFAbstractDataset()                         */
33
/************************************************************************/
34

35
GIFAbstractDataset::~GIFAbstractDataset()
36✔
36

37
{
38
    FlushCache(true);
36✔
39

40
    if (nGCPCount > 0)
36✔
41
    {
42
        GDALDeinitGCPs(nGCPCount, pasGCPList);
×
43
        CPLFree(pasGCPList);
×
44
    }
45

46
    if (hGifFile)
36✔
47
        myDGifCloseFile(hGifFile);
35✔
48

49
    if (fp != nullptr)
36✔
50
        VSIFCloseL(fp);
35✔
51
}
36✔
52

53
/************************************************************************/
54
/*                       GIFCollectXMPMetadata()                        */
55
/************************************************************************/
56

57
/* See §2.1.2 of
58
 * http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf
59
 */
60

61
static CPLString GIFCollectXMPMetadata(VSILFILE *fp)
5✔
62

63
{
64
    CPLString osXMP;
5✔
65

66
    /* Save current position to avoid disturbing GIF stream decoding */
67
    vsi_l_offset nCurOffset = VSIFTellL(fp);
5✔
68

69
    char abyBuffer[2048 + 1];
70

71
    VSIFSeekL(fp, 0, SEEK_SET);
5✔
72

73
    /* Loop over file */
74

75
    int iStartSearchOffset = 1024;
5✔
76
    while (true)
77
    {
78
        int nRead = static_cast<int>(VSIFReadL(abyBuffer + 1024, 1, 1024, fp));
26✔
79
        if (nRead <= 0)
26✔
80
            break;
×
81
        abyBuffer[1024 + nRead] = 0;
26✔
82

83
        int iFoundOffset = -1;
26✔
84
        for (int i = iStartSearchOffset; i < 1024 + nRead - 14; i++)
43,588✔
85
        {
86
            if (memcmp(abyBuffer + i, "\x21\xff\x0bXMP DataXMP", 14) == 0)
43,563✔
87
            {
88
                iFoundOffset = i + 14;
1✔
89
                break;
1✔
90
            }
91
        }
92

93
        iStartSearchOffset = 0;
26✔
94

95
        if (iFoundOffset >= 0)
26✔
96
        {
97
            int nSize = 1024 + nRead - iFoundOffset;
1✔
98
            char *pszXMP = (char *)VSIMalloc(nSize + 1);
1✔
99
            if (pszXMP == nullptr)
1✔
100
                break;
×
101

102
            pszXMP[nSize] = 0;
1✔
103
            memcpy(pszXMP, abyBuffer + iFoundOffset, nSize);
1✔
104

105
            /* Read from file until we find a NUL character */
106
            int nLen = (int)strlen(pszXMP);
1✔
107
            while (nLen == nSize)
5✔
108
            {
109
                char *pszNewXMP = (char *)VSIRealloc(pszXMP, nSize + 1024 + 1);
4✔
110
                if (pszNewXMP == nullptr)
4✔
111
                    break;
×
112
                pszXMP = pszNewXMP;
4✔
113

114
                nRead =
4✔
115
                    static_cast<int>(VSIFReadL(pszXMP + nSize, 1, 1024, fp));
4✔
116
                if (nRead <= 0)
4✔
117
                    break;
×
118

119
                pszXMP[nSize + nRead] = 0;
4✔
120
                nLen += (int)strlen(pszXMP + nSize);
4✔
121
                nSize += nRead;
4✔
122
            }
123

124
            if (nLen > 256 && pszXMP[nLen - 1] == '\x01' &&
1✔
125
                pszXMP[nLen - 2] == '\x02' && pszXMP[nLen - 255] == '\xff' &&
1✔
126
                pszXMP[nLen - 256] == '\x01')
1✔
127
            {
128
                pszXMP[nLen - 256] = 0;
1✔
129

130
                osXMP = pszXMP;
1✔
131
            }
132

133
            VSIFree(pszXMP);
1✔
134

135
            break;
1✔
136
        }
137

138
        if (nRead != 1024)
25✔
139
            break;
4✔
140

141
        memcpy(abyBuffer, abyBuffer + 1024, 1024);
21✔
142
    }
21✔
143

144
    VSIFSeekL(fp, nCurOffset, SEEK_SET);
5✔
145

146
    return osXMP;
10✔
147
}
148

149
/************************************************************************/
150
/*                       CollectXMPMetadata()                           */
151
/************************************************************************/
152

153
void GIFAbstractDataset::CollectXMPMetadata()
5✔
154

155
{
156
    if (fp == nullptr || bHasReadXMPMetadata)
5✔
157
        return;
×
158

159
    CPLString osXMP = GIFCollectXMPMetadata(fp);
5✔
160
    if (!osXMP.empty())
5✔
161
    {
162
        /* Avoid setting the PAM dirty bit just for that */
163
        const int nOldPamFlags = nPamFlags;
1✔
164

165
        char *apszMDList[2];
166
        apszMDList[0] = (char *)osXMP.c_str();
1✔
167
        apszMDList[1] = nullptr;
1✔
168
        SetMetadata(apszMDList, "xml:XMP");
1✔
169

170
        // cppcheck-suppress redundantAssignment
171
        nPamFlags = nOldPamFlags;
1✔
172
    }
173

174
    bHasReadXMPMetadata = TRUE;
5✔
175
}
176

177
/************************************************************************/
178
/*                      GetMetadataDomainList()                         */
179
/************************************************************************/
180

181
char **GIFAbstractDataset::GetMetadataDomainList()
1✔
182
{
183
    return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
1✔
184
                                   TRUE, "xml:XMP", nullptr);
1✔
185
}
186

187
/************************************************************************/
188
/*                           GetMetadata()                              */
189
/************************************************************************/
190

191
char **GIFAbstractDataset::GetMetadata(const char *pszDomain)
64✔
192
{
193
    if (fp == nullptr)
64✔
194
        return nullptr;
×
195
    if (eAccess == GA_ReadOnly && !bHasReadXMPMetadata &&
64✔
196
        (pszDomain != nullptr && EQUAL(pszDomain, "xml:XMP")))
53✔
197
        CollectXMPMetadata();
5✔
198
    return GDALPamDataset::GetMetadata(pszDomain);
64✔
199
}
200

201
/************************************************************************/
202
/*                          GetGeoTransform()                           */
203
/************************************************************************/
204

205
CPLErr GIFAbstractDataset::GetGeoTransform(GDALGeoTransform &gt) const
52✔
206

207
{
208
    if (bGeoTransformValid)
52✔
209
    {
210
        gt = m_gt;
×
211
        return CE_None;
×
212
    }
213

214
    return GDALPamDataset::GetGeoTransform(gt);
52✔
215
}
216

217
/************************************************************************/
218
/*                            GetGCPCount()                             */
219
/************************************************************************/
220

221
int GIFAbstractDataset::GetGCPCount()
10✔
222

223
{
224
    if (nGCPCount > 0)
10✔
225
        return nGCPCount;
×
226

227
    return GDALPamDataset::GetGCPCount();
10✔
228
}
229

230
/************************************************************************/
231
/*                               GetGCPs()                              */
232
/************************************************************************/
233

234
const GDAL_GCP *GIFAbstractDataset::GetGCPs()
×
235

236
{
237
    if (nGCPCount > 0)
×
238
        return pasGCPList;
×
239

240
    return GDALPamDataset::GetGCPs();
×
241
}
242

243
/************************************************************************/
244
/*                            GetFileList()                             */
245
/************************************************************************/
246

247
char **GIFAbstractDataset::GetFileList()
12✔
248

249
{
250
    char **papszFileList = GDALPamDataset::GetFileList();
12✔
251

252
    if (!osWldFilename.empty() &&
12✔
253
        CSLFindString(papszFileList, osWldFilename) == -1)
×
254
    {
255
        papszFileList = CSLAddString(papszFileList, osWldFilename);
×
256
    }
257

258
    return papszFileList;
12✔
259
}
260

261
/************************************************************************/
262
/*                         DetectGeoreferencing()                       */
263
/************************************************************************/
264

265
void GIFAbstractDataset::DetectGeoreferencing(GDALOpenInfo *poOpenInfo)
35✔
266
{
267
    char *pszWldFilename = nullptr;
35✔
268

269
    bGeoTransformValid =
35✔
270
        GDALReadWorldFile2(poOpenInfo->pszFilename, nullptr, m_gt,
70✔
271
                           poOpenInfo->GetSiblingFiles(), &pszWldFilename);
35✔
272
    if (!bGeoTransformValid)
35✔
273
    {
274
        bGeoTransformValid =
35✔
275
            GDALReadWorldFile2(poOpenInfo->pszFilename, ".wld", m_gt,
35✔
276
                               poOpenInfo->GetSiblingFiles(), &pszWldFilename);
35✔
277
    }
278

279
    if (pszWldFilename)
35✔
280
    {
281
        osWldFilename = pszWldFilename;
×
282
        CPLFree(pszWldFilename);
×
283
    }
284
}
35✔
285

286
/************************************************************************/
287
/*                            myDGifOpen()                              */
288
/************************************************************************/
289

290
GifFileType *GIFAbstractDataset::myDGifOpen(void *userPtr, InputFunc readFunc)
68✔
291
{
292
#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
293
    int nErrorCode;
294
    return DGifOpen(userPtr, readFunc, &nErrorCode);
136✔
295
#else
296
    return DGifOpen(userPtr, readFunc);
297
#endif
298
}
299

300
/************************************************************************/
301
/*                          myDGifCloseFile()                           */
302
/************************************************************************/
303

304
int GIFAbstractDataset::myDGifCloseFile(GifFileType *hGifFile)
68✔
305
{
306
#if defined(GIFLIB_MAJOR) &&                                                   \
307
    ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5)
308
    int nErrorCode;
309
    return DGifCloseFile(hGifFile, &nErrorCode);
136✔
310
#else
311
    return DGifCloseFile(hGifFile);
312
#endif
313
}
314

315
/************************************************************************/
316
/*                          myEGifCloseFile()                           */
317
/************************************************************************/
318

319
int GIFAbstractDataset::myEGifCloseFile(GifFileType *hGifFile)
6✔
320
{
321
#if defined(GIFLIB_MAJOR) &&                                                   \
322
    ((GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5)
323
    int nErrorCode;
324
    return EGifCloseFile(hGifFile, &nErrorCode);
12✔
325
#else
326
    return EGifCloseFile(hGifFile);
327
#endif
328
}
329

330
/************************************************************************/
331
/*                           VSIGIFReadFunc()                           */
332
/*                                                                      */
333
/*      Proxy function for reading from GIF file.                       */
334
/************************************************************************/
335

336
int GIFAbstractDataset::ReadFunc(GifFileType *psGFile, GifByteType *pabyBuffer,
9,218✔
337
                                 int nBytesToRead)
338

339
{
340
    return static_cast<int>(
341
        VSIFReadL(pabyBuffer, 1, nBytesToRead, (VSILFILE *)psGFile->UserData));
9,218✔
342
}
343

344
/************************************************************************/
345
/*                          FindFirstImage()                            */
346
/************************************************************************/
347

348
GifRecordType GIFAbstractDataset::FindFirstImage(GifFileType *hGifFile)
39✔
349
{
350
    GifRecordType RecordType = TERMINATE_RECORD_TYPE;
39✔
351

352
    while (DGifGetRecordType(hGifFile, &RecordType) != GIF_ERROR &&
43✔
353
           RecordType != TERMINATE_RECORD_TYPE &&
86✔
354
           RecordType != IMAGE_DESC_RECORD_TYPE)
43✔
355
    {
356
        /* Skip extension records found before IMAGE_DESC_RECORD_TYPE */
357
        if (RecordType == EXTENSION_RECORD_TYPE)
4✔
358
        {
359
            int nFunction;
360
            GifByteType *pExtData = nullptr;
4✔
361
            if (DGifGetExtension(hGifFile, &nFunction, &pExtData) == GIF_ERROR)
4✔
362
                break;
×
363
            while (pExtData != nullptr)
96✔
364
            {
365
                if (DGifGetExtensionNext(hGifFile, &pExtData) == GIF_ERROR)
92✔
366
                    break;
×
367
            }
368
        }
369
    }
370

371
    return RecordType;
39✔
372
}
373

374
/************************************************************************/
375
/*                        GIFAbstractRasterBand()                       */
376
/************************************************************************/
377

378
GIFAbstractRasterBand::GIFAbstractRasterBand(GIFAbstractDataset *poDSIn,
36✔
379
                                             int nBandIn,
380
                                             SavedImage *psSavedImage,
381
                                             int nBackground,
382
                                             int bAdvertiseInterlacedMDI)
36✔
383
    : psImage(psSavedImage), panInterlaceMap(nullptr), poColorTable(nullptr),
384
      nTransparentColor(0)
36✔
385
{
386
    poDS = poDSIn;
36✔
387
    nBand = nBandIn;
36✔
388

389
    eDataType = GDT_Byte;
36✔
390

391
    nBlockXSize = poDS->GetRasterXSize();
36✔
392
    nBlockYSize = 1;
36✔
393

394
    if (psImage == nullptr)
36✔
395
        return;
1✔
396

397
    /* -------------------------------------------------------------------- */
398
    /*      Setup interlacing map if required.                              */
399
    /* -------------------------------------------------------------------- */
400
    panInterlaceMap = nullptr;
35✔
401
    if (psImage->ImageDesc.Interlace)
35✔
402
    {
403
        int iLine = 0;
6✔
404

405
        if (bAdvertiseInterlacedMDI)
6✔
406
            poDS->SetMetadataItem("INTERLACED", "YES", "IMAGE_STRUCTURE");
6✔
407

408
        panInterlaceMap = (int *)CPLCalloc(poDSIn->nRasterYSize, sizeof(int));
6✔
409

410
        for (int i = 0; i < 4; i++)
30✔
411
        {
412
            for (int j = InterlacedOffset[i]; j < poDSIn->nRasterYSize;
67,158✔
413
                 j += InterlacedJumps[i])
67,134✔
414
                panInterlaceMap[j] = iLine++;
67,134✔
415
        }
416
    }
417
    else if (bAdvertiseInterlacedMDI)
29✔
418
    {
419
        poDS->SetMetadataItem("INTERLACED", "NO", "IMAGE_STRUCTURE");
×
420
    }
421

422
    /* -------------------------------------------------------------------- */
423
    /*      Check for transparency.  We just take the first graphic         */
424
    /*      control extension block we find, if any.                        */
425
    /* -------------------------------------------------------------------- */
426
    nTransparentColor = -1;
35✔
427
    for (int iExtBlock = 0; iExtBlock < psImage->ExtensionBlockCount;
127✔
428
         iExtBlock++)
429
    {
430
        if (psImage->ExtensionBlocks[iExtBlock].Function != 0xf9 ||
92✔
431
            psImage->ExtensionBlocks[iExtBlock].ByteCount < 4)
3✔
432
            continue;
89✔
433

434
        unsigned char *pExtData = reinterpret_cast<unsigned char *>(
3✔
435
            psImage->ExtensionBlocks[iExtBlock].Bytes);
3✔
436

437
        /* check if transparent color flag is set */
438
        if (!(pExtData[0] & 0x1))
3✔
439
            continue;
×
440

441
        nTransparentColor = pExtData[3];
3✔
442
    }
443

444
    /* -------------------------------------------------------------------- */
445
    /*      Setup colormap.                                                 */
446
    /* -------------------------------------------------------------------- */
447
    ColorMapObject *psGifCT = psImage->ImageDesc.ColorMap;
35✔
448
    if (psGifCT == nullptr)
35✔
449
        psGifCT = poDSIn->hGifFile->SColorMap;
35✔
450

451
    poColorTable = new GDALColorTable();
35✔
452
    for (int iColor = 0; iColor < psGifCT->ColorCount; iColor++)
3,475✔
453
    {
454
        GDALColorEntry oEntry;
455

456
        oEntry.c1 = psGifCT->Colors[iColor].Red;
3,440✔
457
        oEntry.c2 = psGifCT->Colors[iColor].Green;
3,440✔
458
        oEntry.c3 = psGifCT->Colors[iColor].Blue;
3,440✔
459

460
        if (iColor == nTransparentColor)
3,440✔
461
            oEntry.c4 = 0;
3✔
462
        else
463
            oEntry.c4 = 255;
3,437✔
464

465
        poColorTable->SetColorEntry(iColor, &oEntry);
3,440✔
466
    }
467

468
    /* -------------------------------------------------------------------- */
469
    /*      If we have a background value, return it here.  Some            */
470
    /*      applications might want to treat this as transparent, but in    */
471
    /*      many uses this is inappropriate so we don't return it as        */
472
    /*      nodata or transparent.                                          */
473
    /* -------------------------------------------------------------------- */
474
    if (nBackground != 255)
35✔
475
    {
476
        char szBackground[10];
477

478
        snprintf(szBackground, sizeof(szBackground), "%d", nBackground);
20✔
479
        SetMetadataItem("GIF_BACKGROUND", szBackground);
20✔
480
    }
481
}
482

483
/************************************************************************/
484
/*                       ~GIFAbstractRasterBand()                       */
485
/************************************************************************/
486

487
GIFAbstractRasterBand::~GIFAbstractRasterBand()
36✔
488

489
{
490
    if (poColorTable != nullptr)
36✔
491
        delete poColorTable;
35✔
492

493
    CPLFree(panInterlaceMap);
36✔
494
}
36✔
495

496
/************************************************************************/
497
/*                       GetColorInterpretation()                       */
498
/************************************************************************/
499

500
GDALColorInterp GIFAbstractRasterBand::GetColorInterpretation()
22✔
501

502
{
503
    return GCI_PaletteIndex;
22✔
504
}
505

506
/************************************************************************/
507
/*                           GetColorTable()                            */
508
/************************************************************************/
509

510
GDALColorTable *GIFAbstractRasterBand::GetColorTable()
42✔
511

512
{
513
    return poColorTable;
42✔
514
}
515

516
/************************************************************************/
517
/*                           GetNoDataValue()                           */
518
/************************************************************************/
519

520
double GIFAbstractRasterBand::GetNoDataValue(int *pbSuccess)
44✔
521

522
{
523
    if (pbSuccess != nullptr)
44✔
524
        *pbSuccess = nTransparentColor != -1;
44✔
525

526
    return nTransparentColor;
44✔
527
}
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