• 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

78.26
/apps/gdal_create.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Utilities
4
 * Purpose:  GDAL Raster creation utility
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2020, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12

13
#include "cpl_string.h"
14
#include "gdal_version.h"
15
#include "gdal_priv.h"
16
#include "gdal.h"
17
#include "commonutils.h"
18
#include "gdalargumentparser.h"
19
#include "ogr_spatialref.h"
20

21
#include <cstdlib>
22
#include <memory>
23
#include <vector>
24

25
/**
26
 * @brief Makes sure the GDAL library is properly cleaned up before exiting.
27
 * @param nCode exit code
28
 * @todo Move to API
29
 */
30
static void GDALExit(int nCode)
3✔
31
{
32
    GDALDestroy();
3✔
33
    exit(nCode);
3✔
34
}
35

36
/************************************************************************/
37
/*                     GDALCreateOptions                               */
38
/************************************************************************/
39

40
struct GDALCreateOptions
41
{
42
    int nBandCount = -1;
43
    int nPixels = 0;
44
    bool bPixelsSet{false};
45
    int nLines = 0;
46
    GDALDataType eDT = GDT_Unknown;
47
    double dfULX = 0;
48
    double dfULY = 0;
49
    double dfLRX = 0;
50
    double dfLRY = 0;
51
    int nULCounter{0};
52
    bool bGeoTransform = false;
53
    std::string osOutputSRS;
54
    CPLStringList aosMetadata;
55
    std::vector<double> adfBurnValues;
56
    bool bQuiet = false;
57
    bool bSetNoData = false;
58
    std::string osNoData;
59
    std::string osOutputFilename;
60
    std::string osInputFilename;
61
    std::string osFormat;
62
    CPLStringList aosCreateOptions;
63
};
64

65
/************************************************************************/
66
/*                   GDALCreateAppOptionsGetParser()                   */
67
/************************************************************************/
68

69
static std::unique_ptr<GDALArgumentParser>
70
GDALCreateAppOptionsGetParser(GDALCreateOptions *psOptions)
10✔
71
{
72
    auto argParser = std::make_unique<GDALArgumentParser>(
73
        "gdal_create", /* bForBinary */ true);
10✔
74

75
    argParser->add_description(
10✔
76
        _("Create a raster file (without source dataset)."));
10✔
77

78
    argParser->add_epilog(_(
10✔
79
        "For more details, consult the full documentation for the gdal_create "
80
        "utility: http://gdal.org/gdal_create.html"));
10✔
81

82
    argParser->add_output_type_argument(psOptions->eDT);
10✔
83

84
    argParser->add_output_format_argument(psOptions->osFormat);
10✔
85

86
    argParser->add_argument("-outsize")
10✔
87
        .metavar("<xsize> <ysize>")
20✔
88
        .nargs(2)
10✔
89
        .scan<'i', int>()
10✔
90
        .action(
91
            [psOptions](const std::string &s)
24✔
92
            {
93
                if (!psOptions->bPixelsSet)
12✔
94
                {
95
                    psOptions->nPixels = atoi(s.c_str());
6✔
96
                    psOptions->bPixelsSet = true;
6✔
97
                }
98
                else
99
                {
100
                    psOptions->nLines = atoi(s.c_str());
6✔
101
                }
102
            })
10✔
103
        .help(_("Set the size of the output file."));
10✔
104

105
    argParser->add_argument("-bands")
10✔
106
        .metavar("<count>")
20✔
107
        .store_into(psOptions->nBandCount)
10✔
108
        .help(_("Set the number of bands in the output file."));
10✔
109

110
    argParser->add_argument("-burn").metavar("<value>").append().help(
20✔
111
        _("A fixed value to burn into a band. A list of "
112
          "-burn options can be supplied, one per band being written to."));
10✔
113

114
    argParser->add_argument("-a_srs")
10✔
115
        .metavar("<srs_def>")
20✔
116
        .store_into(psOptions->osOutputSRS)
10✔
117
        .help(_("Override the projection for the output file. "));
10✔
118

119
    argParser->add_argument("-a_ullr")
10✔
120
        .metavar("<ulx> <uly> <lrx> <lry>")
20✔
121
        .scan<'g', double>()
10✔
122
        .nargs(4)
10✔
123
        .action(
124
            [psOptions](const std::string &s)
27✔
125
            {
126
                switch (psOptions->nULCounter++)
12✔
127
                {
128
                    case 0:
3✔
129
                        psOptions->bGeoTransform = true;
3✔
130
                        psOptions->dfULX = CPLAtofM(s.c_str());
3✔
131
                        break;
3✔
132
                    case 1:
3✔
133
                        psOptions->dfULY = CPLAtofM(s.c_str());
3✔
134
                        break;
3✔
135
                    case 2:
3✔
136
                        psOptions->dfLRX = CPLAtofM(s.c_str());
3✔
137
                        break;
3✔
138
                    case 3:
3✔
139
                        psOptions->dfLRY = CPLAtof(s.c_str());
3✔
140
                        break;
3✔
141
                }
142
            })
10✔
143
        .help(_("Assign the georeferenced bounds of the output file. "));
10✔
144

145
    argParser->add_argument("-a_nodata")
10✔
146
        .metavar("<value>")
20✔
147
        .scan<'g', double>()
10✔
148
        .action(
149
            [psOptions](const std::string &s)
4✔
150
            {
151
                psOptions->bSetNoData = true;
4✔
152
                psOptions->osNoData = s;
4✔
153
            })
10✔
154
        .help(_("Assign a specified nodata value to output bands."));
10✔
155

156
    argParser->add_metadata_item_options_argument(psOptions->aosMetadata);
10✔
157

158
    argParser->add_creation_options_argument(psOptions->aosCreateOptions);
10✔
159

160
    argParser->add_quiet_argument(&psOptions->bQuiet);
10✔
161

162
    argParser->add_argument("-if")
10✔
163
        .metavar("<input_dataset>")
20✔
164
        .store_into(psOptions->osInputFilename)
10✔
165
        .help(_("Name of GDAL input dataset that serves as a template for "
166
                "default values of options -outsize, -bands, -ot, -a_srs, "
167
                "-a_ullr and -a_nodata."));
10✔
168

169
    argParser->add_argument("out_dataset")
10✔
170
        .metavar("<out_dataset>")
20✔
171
        .store_into(psOptions->osOutputFilename)
10✔
172
        .help(_("Name of the output dataset to create."));
10✔
173

174
    return argParser;
10✔
175
}
176

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

181
MAIN_START(argc, argv)
11✔
182

183
{
184
    /* Check strict compilation and runtime library version as we use C++ API */
185
    if (!GDAL_CHECK_VERSION(argv[0]))
11✔
186
        exit(1);
×
187

188
    EarlySetConfigOptions(argc, argv);
11✔
189

190
    /* -------------------------------------------------------------------- */
191
    /*      Register standard GDAL drivers, and process generic GDAL        */
192
    /*      command options.                                                */
193
    /* -------------------------------------------------------------------- */
194
    GDALAllRegister();
11✔
195

196
    argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
11✔
197
    if (argc < 1)
11✔
198
        GDALExit(-argc);
1✔
199

200
    if (argc < 2)
10✔
201
    {
202
        try
203
        {
204
            GDALCreateOptions sOptions;
×
205
            auto argParser = GDALCreateAppOptionsGetParser(&sOptions);
×
206
            fprintf(stderr, "%s\n", argParser->usage().c_str());
×
207
        }
208
        catch (const std::exception &err)
×
209
        {
210
            CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
×
211
                     err.what());
×
212
        }
213
        CSLDestroy(argv);
×
214
        GDALExit(1);
×
215
    }
216

217
    GDALCreateOptions sOptions;
18✔
218

219
    CPLStringList aosArgv;
18✔
220
    for (int iArg = 1; iArg < argc; iArg++)
111✔
221
    {
222
        if (iArg + 1 < argc && EQUAL(argv[iArg], "-burn"))
101✔
223
        {
224
            ++iArg;
4✔
225
            while (true)
226
            {
227
                if (strchr(argv[iArg], ' '))
5✔
228
                {
229
                    const CPLStringList aosTokens(
230
                        CSLTokenizeString(argv[iArg]));
2✔
231
                    for (int i = 0; i < aosTokens.size(); i++)
3✔
232
                    {
233
                        char *endptr = nullptr;
2✔
234
                        sOptions.adfBurnValues.push_back(
2✔
235
                            CPLStrtodM(aosTokens[i], &endptr));
2✔
236
                        if (endptr != aosTokens[i] + strlen(aosTokens[i]))
2✔
237
                        {
238
                            fprintf(stderr, "Invalid value for -burn\n");
×
239
                            CSLDestroy(argv);
×
240
                            GDALExit(1);
×
241
                        }
242
                    }
243
                }
244
                else
245
                {
246
                    char *endptr = nullptr;
4✔
247
                    sOptions.adfBurnValues.push_back(
4✔
248
                        CPLStrtodM(argv[iArg], &endptr));
4✔
249
                    if (endptr != argv[iArg] + strlen(argv[iArg]))
4✔
250
                    {
251
                        fprintf(stderr, "Invalid value for -burn\n");
×
252
                        CSLDestroy(argv);
×
253
                        GDALExit(1);
×
254
                    }
255
                }
256
                if (iArg + 1 < argc &&
10✔
257
                    CPLGetValueType(argv[iArg + 1]) != CPL_VALUE_STRING)
5✔
258
                {
259
                    ++iArg;
1✔
260
                }
261
                else
262
                {
263
                    break;
4✔
264
                }
265
            }
5✔
266
        }
267
        else
268
        {
269
            aosArgv.AddString(argv[iArg]);
97✔
270
        }
271
    }
272
    CSLDestroy(argv);
10✔
273

274
    try
275
    {
276

277
        auto argParser = GDALCreateAppOptionsGetParser(&sOptions);
20✔
278
        argParser->parse_args_without_binary_name(aosArgv.List());
10✔
279
    }
280
    catch (const std::exception &error)
×
281
    {
282
        CPLError(CE_Failure, CPLE_AppDefined, "%s", error.what());
×
283
        GDALExit(1);
×
284
    }
285

286
    GDALGeoTransform gt;
10✔
287
    if (sOptions.bGeoTransform && sOptions.nPixels > 0 && sOptions.nLines > 0)
10✔
288
    {
289
        gt[0] = sOptions.dfULX;
3✔
290
        gt[1] = (sOptions.dfLRX - sOptions.dfULX) / sOptions.nPixels;
3✔
291
        gt[2] = 0;
3✔
292
        gt[3] = sOptions.dfULY;
3✔
293
        gt[4] = 0;
3✔
294
        gt[5] = (sOptions.dfLRY - sOptions.dfULY) / sOptions.nLines;
3✔
295
    }
296

297
    std::unique_ptr<GDALDataset> poInputDS;
×
298
    if (!sOptions.osInputFilename.empty())
10✔
299
    {
300
        poInputDS.reset(
4✔
301
            GDALDataset::Open(sOptions.osInputFilename.c_str(),
302
                              GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
303
        if (poInputDS == nullptr)
4✔
304
        {
305
            GDALExit(1);
1✔
306
        }
307
        if (sOptions.nPixels == 0)
3✔
308
        {
309
            sOptions.nPixels = poInputDS->GetRasterXSize();
2✔
310
            sOptions.nLines = poInputDS->GetRasterYSize();
2✔
311
        }
312
        if (sOptions.nBandCount < 0)
3✔
313
        {
314
            sOptions.nBandCount = poInputDS->GetRasterCount();
2✔
315
        }
316
        if (sOptions.eDT == GDT_Unknown && poInputDS->GetRasterCount() > 0)
3✔
317
        {
318
            sOptions.eDT = poInputDS->GetRasterBand(1)->GetRasterDataType();
3✔
319
        }
320
        if (sOptions.osOutputSRS.empty())
3✔
321
        {
322
            sOptions.osOutputSRS = poInputDS->GetProjectionRef();
3✔
323
        }
324
        if (!(sOptions.bGeoTransform && sOptions.nPixels > 0 &&
3✔
325
              sOptions.nLines > 0))
×
326
        {
327
            if (poInputDS->GetGeoTransform(gt) == CE_None)
3✔
328
            {
329
                sOptions.bGeoTransform = true;
2✔
330
            }
331
        }
332
        if (!sOptions.bSetNoData && poInputDS->GetRasterCount() > 0)
3✔
333
        {
334
            if (sOptions.eDT == GDT_Int64)
2✔
335
            {
336
                int noData;
337
                const auto nNoDataValue =
338
                    poInputDS->GetRasterBand(1)->GetNoDataValueAsInt64(&noData);
×
339
                sOptions.bSetNoData = noData;
×
340
                if (sOptions.bSetNoData)
×
341
                    sOptions.osNoData = CPLSPrintf(
342
                        CPL_FRMT_GIB, static_cast<GIntBig>(nNoDataValue));
×
343
            }
344
            else if (sOptions.eDT == GDT_UInt64)
2✔
345
            {
346
                int noData;
347
                const auto nNoDataValue =
348
                    poInputDS->GetRasterBand(1)->GetNoDataValueAsUInt64(
×
349
                        &noData);
×
350
                sOptions.bSetNoData = noData;
×
351
                if (sOptions.bSetNoData)
×
352
                    sOptions.osNoData = CPLSPrintf(
353
                        CPL_FRMT_GUIB, static_cast<GUIntBig>(nNoDataValue));
×
354
            }
355
            else
356
            {
357
                int noData;
358
                const double dfNoDataValue =
359
                    poInputDS->GetRasterBand(1)->GetNoDataValue(&noData);
2✔
360
                sOptions.bSetNoData = noData;
2✔
361
                if (sOptions.bSetNoData)
2✔
362
                    sOptions.osNoData = CPLSPrintf("%.18g", dfNoDataValue);
×
363
            }
364
        }
365
    }
366

367
    GDALDriverH hDriver = GDALGetDriverByName(
18✔
368
        sOptions.osFormat.empty()
9✔
369
            ? GetOutputDriverForRaster(sOptions.osOutputFilename.c_str())
16✔
370
                  .c_str()
7✔
371
            : sOptions.osFormat.c_str());
2✔
372

373
    if (hDriver == nullptr)
9✔
374
    {
375
        fprintf(stderr, "Output driver not found.\n");
×
376
        GDALExit(1);
×
377
    }
378
    const bool bHasCreate =
379
        GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, nullptr) != nullptr;
9✔
380
    if (!bHasCreate &&
11✔
381
        GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATECOPY, nullptr) == nullptr)
2✔
382
    {
383
        fprintf(stderr, "This driver has no creation capabilities.\n");
1✔
384
        GDALExit(1);
1✔
385
    }
386
    GDALDriverH hTmpDriver = GDALGetDriverByName("MEM");
8✔
387
    if (!bHasCreate && hTmpDriver == nullptr)
8✔
388
    {
389
        fprintf(stderr, "MEM driver not available.\n");
×
390
        GDALExit(1);
×
391
    }
392

393
    if (sOptions.nPixels != 0 && sOptions.eDT == GDT_Unknown)
8✔
394
    {
395
        sOptions.eDT = GDT_Byte;
1✔
396
    }
397
    if (sOptions.nBandCount < 0)
8✔
398
    {
399
        sOptions.nBandCount = sOptions.eDT == GDT_Unknown ? 0 : 1;
2✔
400
    }
401
    GDALDatasetH hDS = GDALCreate(
15✔
402
        bHasCreate ? hDriver : hTmpDriver, sOptions.osOutputFilename.c_str(),
403
        sOptions.nPixels, sOptions.nLines, sOptions.nBandCount, sOptions.eDT,
404
        bHasCreate ? sOptions.aosCreateOptions.List() : nullptr);
7✔
405

406
    if (hDS == nullptr)
8✔
407
    {
408
        GDALExit(1);
×
409
    }
410

411
    if (!sOptions.osOutputSRS.empty() &&
13✔
412
        !EQUAL(sOptions.osOutputSRS.c_str(), "NONE"))
5✔
413
    {
414
        OGRSpatialReference oSRS;
10✔
415
        oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
5✔
416

417
        if (oSRS.SetFromUserInput(sOptions.osOutputSRS.c_str()) != OGRERR_NONE)
5✔
418
        {
419
            CPLError(CE_Failure, CPLE_AppDefined,
×
420
                     "Failed to process SRS definition: %s",
421
                     sOptions.osOutputSRS.c_str());
422
            GDALExit(1);
×
423
        }
424

425
        char *pszSRS = nullptr;
5✔
426
        oSRS.exportToWkt(&pszSRS);
5✔
427

428
        if (GDALSetProjection(hDS, pszSRS) != CE_None)
5✔
429
        {
430
            CPLFree(pszSRS);
×
431
            GDALClose(hDS);
×
432
            GDALExit(1);
×
433
        }
434
        CPLFree(pszSRS);
5✔
435
    }
436
    if (sOptions.bGeoTransform)
8✔
437
    {
438
        if (sOptions.nPixels == 0)
5✔
439
        {
440
            fprintf(stderr,
×
441
                    "-outsize must be specified when -a_ullr is used.\n");
442
            GDALClose(hDS);
×
443
            GDALExit(1);
×
444
        }
445
        if (GDALDataset::FromHandle(hDS)->SetGeoTransform(gt) != CE_None)
5✔
446
        {
447
            GDALClose(hDS);
×
448
            GDALExit(1);
×
449
        }
450
    }
451
    else if (poInputDS && poInputDS->GetGCPCount() > 0)
3✔
452
    {
453
        GDALDataset::FromHandle(hDS)->SetGCPs(poInputDS->GetGCPCount(),
2✔
454
                                              poInputDS->GetGCPs(),
1✔
455
                                              poInputDS->GetGCPSpatialRef());
1✔
456
    }
457

458
    if (!sOptions.aosMetadata.empty())
8✔
459
    {
460
        GDALSetMetadata(hDS, sOptions.aosMetadata.List(), nullptr);
3✔
461
    }
462
    const int nBands = GDALGetRasterCount(hDS);
8✔
463
    if (sOptions.bSetNoData)
8✔
464
    {
465
        for (int i = 0; i < nBands; i++)
15✔
466
        {
467
            auto hBand = GDALGetRasterBand(hDS, i + 1);
11✔
468
            if (sOptions.eDT == GDT_Int64)
11✔
469
            {
470
                GDALSetRasterNoDataValueAsInt64(
×
471
                    hBand, static_cast<int64_t>(std::strtoll(
×
472
                               sOptions.osNoData.c_str(), nullptr, 10)));
473
            }
474
            else if (sOptions.eDT == GDT_UInt64)
11✔
475
            {
476
                GDALSetRasterNoDataValueAsUInt64(
×
477
                    hBand, static_cast<uint64_t>(std::strtoull(
×
478
                               sOptions.osNoData.c_str(), nullptr, 10)));
479
            }
480
            else
481
            {
482
                GDALSetRasterNoDataValue(hBand,
11✔
483
                                         CPLAtofM(sOptions.osNoData.c_str()));
484
            }
485
        }
486
    }
487
    if (!sOptions.adfBurnValues.empty())
8✔
488
    {
489
        for (int i = 0; i < nBands; i++)
12✔
490
        {
491
            GDALFillRaster(GDALGetRasterBand(hDS, i + 1),
9✔
492
                           i < static_cast<int>(sOptions.adfBurnValues.size())
9✔
493
                               ? sOptions.adfBurnValues[i]
6✔
494
                               : sOptions.adfBurnValues.back(),
3✔
495
                           0);
496
        }
497
    }
498

499
    bool bHasGotErr = false;
8✔
500
    if (!bHasCreate)
8✔
501
    {
502
        GDALDatasetH hOutDS = GDALCreateCopy(
2✔
503
            hDriver, sOptions.osOutputFilename.c_str(), hDS, false,
504
            sOptions.aosCreateOptions.List(),
1✔
505
            sOptions.bQuiet ? GDALDummyProgress : GDALTermProgress, nullptr);
1✔
506
        if (hOutDS == nullptr)
1✔
507
        {
508
            GDALClose(hDS);
×
509
            GDALExit(1);
×
510
        }
511
        if (GDALClose(hOutDS) != CE_None)
1✔
512
        {
513
            bHasGotErr = true;
×
514
        }
515
    }
516

517
    const bool bWasFailureBefore = (CPLGetLastErrorType() == CE_Failure);
8✔
518
    if (GDALClose(hDS) != CE_None)
8✔
519
        bHasGotErr = true;
×
520
    if (!bWasFailureBefore && CPLGetLastErrorType() == CE_Failure)
8✔
521
    {
522
        bHasGotErr = true;
×
523
    }
524

525
    return bHasGotErr ? 1 : 0;
8✔
526
}
527

528
MAIN_END
×
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