• 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

84.76
/frmts/raw/pnmdataset.cpp
1
/******************************************************************************
2
 *
3
 * Project:  PNM Driver
4
 * Purpose:  Portable anymap file format implementation
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2001, Frank Warmerdam
9
 * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_string.h"
15
#include "gdal_frmts.h"
16
#include "rawdataset.h"
17

18
#include <algorithm>
19
#include <cctype>
20

21
/************************************************************************/
22
/* ==================================================================== */
23
/*                              PNMDataset                              */
24
/* ==================================================================== */
25
/************************************************************************/
26

27
class PNMDataset final : public RawDataset
28
{
29
    VSILFILE *fpImage = nullptr;  // Image data file.
30

31
    bool bGeoTransformValid{};
32
    GDALGeoTransform m_gt{};
33

34
    CPL_DISALLOW_COPY_ASSIGN(PNMDataset)
35

36
    CPLErr Close() override;
37

38
  public:
39
    PNMDataset() = default;
69✔
40
    ~PNMDataset() override;
41

42
    CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
43

44
    static int Identify(GDALOpenInfo *);
45
    static GDALDataset *Open(GDALOpenInfo *);
46
    static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
47
                               int nBandsIn, GDALDataType eType,
48
                               char **papszOptions);
49
};
50

51
/************************************************************************/
52
/*                            ~PNMDataset()                            */
53
/************************************************************************/
54

55
PNMDataset::~PNMDataset()
138✔
56

57
{
58
    PNMDataset::Close();
69✔
59
}
138✔
60

61
/************************************************************************/
62
/*                              Close()                                 */
63
/************************************************************************/
64

65
CPLErr PNMDataset::Close()
135✔
66
{
67
    CPLErr eErr = CE_None;
135✔
68
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
135✔
69
    {
70
        if (PNMDataset::FlushCache(true) != CE_None)
69✔
71
            eErr = CE_Failure;
×
72

73
        if (fpImage)
69✔
74
        {
75
            if (VSIFCloseL(fpImage) != 0)
69✔
76
            {
77
                CPLError(CE_Failure, CPLE_FileIO, "I/O error");
×
78
                eErr = CE_Failure;
×
79
            }
80
        }
81

82
        if (GDALPamDataset::Close() != CE_None)
69✔
83
            eErr = CE_Failure;
×
84
    }
85
    return eErr;
135✔
86
}
87

88
/************************************************************************/
89
/*                          GetGeoTransform()                           */
90
/************************************************************************/
91

92
CPLErr PNMDataset::GetGeoTransform(GDALGeoTransform &gt) const
4✔
93

94
{
95
    if (bGeoTransformValid)
4✔
96
    {
97
        gt = m_gt;
×
98
        return CE_None;
×
99
    }
100

101
    return CE_Failure;
4✔
102
}
103

104
/************************************************************************/
105
/*                              Identify()                              */
106
/************************************************************************/
107

108
int PNMDataset::Identify(GDALOpenInfo *poOpenInfo)
57,377✔
109

110
{
111
    /* -------------------------------------------------------------------- */
112
    /*      Verify that this is a _raw_ ppm or pgm file.  Note, we don't    */
113
    /*      support ascii files, or pbm (1bit) files.                       */
114
    /* -------------------------------------------------------------------- */
115
    if (poOpenInfo->nHeaderBytes < 10 || poOpenInfo->fpL == nullptr)
57,377✔
116
        return FALSE;
53,503✔
117

118
    if (poOpenInfo->pabyHeader[0] != 'P' ||
3,874✔
119
        (poOpenInfo->pabyHeader[2] != ' ' &&   // XXX: Magick number
259✔
120
         poOpenInfo->pabyHeader[2] != '\t' &&  // may be followed
259✔
121
         poOpenInfo->pabyHeader[2] != '\n' &&  // any of the blank
259✔
122
         poOpenInfo->pabyHeader[2] != '\r'))   // characters
144✔
123
        return FALSE;
3,759✔
124

125
    if (poOpenInfo->pabyHeader[1] != '5' && poOpenInfo->pabyHeader[1] != '6')
115✔
126
        return FALSE;
×
127

128
    return TRUE;
115✔
129
}
130

131
/************************************************************************/
132
/*                                Open()                                */
133
/************************************************************************/
134

135
GDALDataset *PNMDataset::Open(GDALOpenInfo *poOpenInfo)
69✔
136

137
{
138
    /* -------------------------------------------------------------------- */
139
    /*      Verify that this is a _raw_ ppm or pgm file.  Note, we don't    */
140
    /*      support ascii files, or pbm (1bit) files.                       */
141
    /* -------------------------------------------------------------------- */
142
    if (!Identify(poOpenInfo))
69✔
143
        return nullptr;
×
144

145
    /* -------------------------------------------------------------------- */
146
    /*      Parse out the tokens from the header.                           */
147
    /* -------------------------------------------------------------------- */
148
    const char *pszSrc = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
69✔
149
    char szToken[512] = {'\0'};
69✔
150
    int iToken = 0;
69✔
151
    int nWidth = -1;
69✔
152
    int nHeight = -1;
69✔
153
    int nMaxValue = -1;
69✔
154

155
    int iIn = 2;
69✔
156
    while (iIn < poOpenInfo->nHeaderBytes && iToken < 3)
276✔
157
    {
158
        unsigned int iOut = 0;
207✔
159
        szToken[0] = '\0';
207✔
160
        while (iOut < sizeof(szToken) && iIn < poOpenInfo->nHeaderBytes)
811✔
161
        {
162
            if (pszSrc[iIn] == '#')
811✔
163
            {
164
                while (iIn < poOpenInfo->nHeaderBytes - 1 &&
×
165
                       pszSrc[iIn] != 10 && pszSrc[iIn] != 13)
×
166
                    iIn++;
×
167
            }
168

169
            if (iOut != 0 && isspace(static_cast<unsigned char>(pszSrc[iIn])))
811✔
170
            {
171
                szToken[iOut] = '\0';
207✔
172

173
                if (iToken == 0)
207✔
174
                    nWidth = atoi(szToken);
69✔
175
                else if (iToken == 1)
138✔
176
                    nHeight = atoi(szToken);
69✔
177
                else if (iToken == 2)
69✔
178
                    nMaxValue = atoi(szToken);
69✔
179

180
                iToken++;
207✔
181
                iIn++;
207✔
182
                break;
207✔
183
            }
184

185
            else if (!isspace(static_cast<unsigned char>(pszSrc[iIn])))
604✔
186
            {
187
                szToken[iOut++] = pszSrc[iIn];
535✔
188
            }
189

190
            iIn++;
604✔
191
        }
192
    }
193

194
    CPLDebug("PNM", "PNM header contains: width=%d, height=%d, maxval=%d",
69✔
195
             nWidth, nHeight, nMaxValue);
196

197
    if (iToken != 3 || nWidth < 1 || nHeight < 1 || nMaxValue < 1)
69✔
198
        return nullptr;
×
199

200
    /* -------------------------------------------------------------------- */
201
    /*      Create a corresponding GDALDataset.                             */
202
    /* -------------------------------------------------------------------- */
203
    auto poDS = std::make_unique<PNMDataset>();
138✔
204

205
    /* -------------------------------------------------------------------- */
206
    /*      Capture some information from the file that is of interest.     */
207
    /* -------------------------------------------------------------------- */
208
    poDS->nRasterXSize = nWidth;
69✔
209
    poDS->nRasterYSize = nHeight;
69✔
210

211
    // Borrow file pointer
212
    std::swap(poDS->fpImage, poOpenInfo->fpL);
69✔
213

214
    poDS->eAccess = poOpenInfo->eAccess;
69✔
215

216
    /* -------------------------------------------------------------------- */
217
    /*      Create band information objects.                                */
218
    /* -------------------------------------------------------------------- */
219

220
    GDALDataType eDataType = GDT_Unknown;
69✔
221
    if (nMaxValue < 256)
69✔
222
        eDataType = GDT_Byte;
55✔
223
    else
224
        eDataType = GDT_UInt16;
14✔
225

226
    const int iPixelSize = GDALGetDataTypeSizeBytes(eDataType);
69✔
227

228
    if (poOpenInfo->pabyHeader[1] == '5')
69✔
229
    {
230
        if (nWidth > INT_MAX / iPixelSize)
52✔
231
        {
232
            CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
×
233
            return nullptr;
×
234
        }
235
        auto poBand = RawRasterBand::Create(
236
            poDS.get(), 1, poDS->fpImage, iIn, iPixelSize, nWidth * iPixelSize,
104✔
237
            eDataType, RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
238
            RawRasterBand::OwnFP::NO);
52✔
239
        if (!poBand)
52✔
240
            return nullptr;
×
241
        poBand->SetColorInterpretation(GCI_GrayIndex);
52✔
242
        poDS->SetBand(1, std::move(poBand));
52✔
243
    }
244
    else
245
    {
246
        if (nWidth > INT_MAX / (3 * iPixelSize))
17✔
247
        {
248
            CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
×
249
            return nullptr;
×
250
        }
251
        for (int i = 0; i < 3; ++i)
68✔
252
        {
253
            auto poBand = RawRasterBand::Create(
254
                poDS.get(), i + 1, poDS->fpImage, iIn + i * iPixelSize,
102✔
255
                3 * iPixelSize, nWidth * 3 * iPixelSize, eDataType,
51✔
256
                RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
257
                RawRasterBand::OwnFP::NO);
51✔
258
            if (!poBand)
51✔
259
                return nullptr;
×
260
            poBand->SetColorInterpretation(
51✔
261
                static_cast<GDALColorInterp>(GCI_RedBand + i));
51✔
262
            poDS->SetBand(i + 1, std::move(poBand));
51✔
263
        }
264
    }
265

266
    /* -------------------------------------------------------------------- */
267
    /*      Check for world file.                                           */
268
    /* -------------------------------------------------------------------- */
269
    poDS->bGeoTransformValid = CPL_TO_BOOL(
138✔
270
        GDALReadWorldFile(poOpenInfo->pszFilename, ".wld", poDS->m_gt.data()));
138✔
271

272
    /* -------------------------------------------------------------------- */
273
    /*      Initialize any PAM information.                                 */
274
    /* -------------------------------------------------------------------- */
275
    poDS->SetDescription(poOpenInfo->pszFilename);
69✔
276
    poDS->TryLoadXML();
69✔
277

278
    /* -------------------------------------------------------------------- */
279
    /*      Check for overviews.                                            */
280
    /* -------------------------------------------------------------------- */
281
    poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
69✔
282

283
    return poDS.release();
69✔
284
}
285

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

290
GDALDataset *PNMDataset::Create(const char *pszFilename, int nXSize, int nYSize,
65✔
291
                                int nBandsIn, GDALDataType eType,
292
                                char **papszOptions)
293

294
{
295
    /* -------------------------------------------------------------------- */
296
    /*      Verify input options.                                           */
297
    /* -------------------------------------------------------------------- */
298
    if (eType != GDT_Byte && eType != GDT_UInt16)
65✔
299
    {
300
        CPLError(CE_Failure, CPLE_AppDefined,
33✔
301
                 "Attempt to create PNM dataset with an illegal "
302
                 "data type (%s), only Byte and UInt16 supported.",
303
                 GDALGetDataTypeName(eType));
304

305
        return nullptr;
33✔
306
    }
307

308
    if (nBandsIn != 1 && nBandsIn != 3)
32✔
309
    {
310
        CPLError(CE_Failure, CPLE_AppDefined,
7✔
311
                 "Attempt to create PNM dataset with an illegal number"
312
                 "of bands (%d).  Must be 1 (greyscale) or 3 (RGB).",
313
                 nBandsIn);
314

315
        return nullptr;
7✔
316
    }
317
    const CPLString osExt(CPLGetExtensionSafe(pszFilename));
50✔
318
    if (nBandsIn == 1)
25✔
319
    {
320
        if (!EQUAL(osExt, "PGM"))
18✔
321
        {
322
            CPLError(CE_Warning, CPLE_AppDefined,
13✔
323
                     "Extension for a 1-band netpbm file should be .pgm");
324
        }
325
    }
326
    else /* if( nBands == 3 ) */
327
    {
328
        if (!EQUAL(osExt, "PPM"))
7✔
329
        {
330
            CPLError(CE_Warning, CPLE_AppDefined,
5✔
331
                     "Extension for a 3-band netpbm file should be .ppm");
332
        }
333
    }
334

335
    /* -------------------------------------------------------------------- */
336
    /*      Try to create the file.                                         */
337
    /* -------------------------------------------------------------------- */
338
    VSILFILE *fp = VSIFOpenL(pszFilename, "wb");
25✔
339
    if (fp == nullptr)
25✔
340
    {
341
        CPLError(CE_Failure, CPLE_OpenFailed,
2✔
342
                 "Attempt to create file `%s' failed.", pszFilename);
343
        return nullptr;
2✔
344
    }
345

346
    /* -------------------------------------------------------------------- */
347
    /*      Write out the header.                                           */
348
    /* -------------------------------------------------------------------- */
349
    int nMaxValue = 0;
23✔
350

351
    const char *pszMaxValue = CSLFetchNameValue(papszOptions, "MAXVAL");
23✔
352
    if (pszMaxValue)
23✔
353
    {
354
        nMaxValue = atoi(pszMaxValue);
×
355
        if (eType == GDT_Byte && (nMaxValue > 255 || nMaxValue < 0))
×
356
            nMaxValue = 255;
×
357
        else if (nMaxValue > 65535 || nMaxValue < 0)
×
358
            nMaxValue = 65535;
×
359
    }
360
    else
361
    {
362
        if (eType == GDT_Byte)
23✔
363
            nMaxValue = 255;
18✔
364
        else
365
            nMaxValue = 65535;
5✔
366
    }
367

368
    char szHeader[500] = {'\0'};
23✔
369

370
    if (nBandsIn == 3)
23✔
371
        snprintf(szHeader, sizeof(szHeader), "P6\n%d %d\n%d\n", nXSize, nYSize,
7✔
372
                 nMaxValue);
373
    else
374
        snprintf(szHeader, sizeof(szHeader), "P5\n%d %d\n%d\n", nXSize, nYSize,
16✔
375
                 nMaxValue);
376

377
    bool bOK = VSIFWriteL(szHeader, strlen(szHeader) + 2, 1, fp) == 1;
23✔
378
    if (VSIFCloseL(fp) != 0)
23✔
379
        bOK = false;
×
380

381
    if (!bOK)
23✔
382
        return nullptr;
×
383

384
    GDALOpenInfo oOpenInfo(pszFilename, GA_Update);
46✔
385
    return Open(&oOpenInfo);
23✔
386
}
387

388
/************************************************************************/
389
/*                         GDALRegister_PNM()                           */
390
/************************************************************************/
391

392
void GDALRegister_PNM()
1,911✔
393

394
{
395
    if (GDALGetDriverByName("PNM") != nullptr)
1,911✔
396
        return;
282✔
397

398
    GDALDriver *poDriver = new GDALDriver();
1,629✔
399

400
    poDriver->SetDescription("PNM");
1,629✔
401
    poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1,629✔
402
    poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
1,629✔
403
                              "Portable Pixmap Format (netpbm)");
1,629✔
404
    poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pnm.html");
1,629✔
405
    // pgm : grey
406
    // ppm : RGB
407
    // pnm : ??
408
    poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "pgm ppm pnm");
1,629✔
409
    poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/x-portable-anymap");
1,629✔
410
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte UInt16");
1,629✔
411
    poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST,
1,629✔
412
                              "<CreationOptionList>"
413
                              "   <Option name='MAXVAL' type='unsigned int' "
414
                              "description='Maximum color value'/>"
415
                              "</CreationOptionList>");
1,629✔
416
    poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1,629✔
417

418
    poDriver->pfnOpen = PNMDataset::Open;
1,629✔
419
    poDriver->pfnCreate = PNMDataset::Create;
1,629✔
420
    poDriver->pfnIdentify = PNMDataset::Identify;
1,629✔
421

422
    GetGDALDriverManager()->RegisterDriver(poDriver);
1,629✔
423
}
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