Coverage Report

Created: 2026-05-16 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdal_misc.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Free standing functions for GDAL.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
16
#include <cctype>
17
#include <cerrno>
18
#include <clocale>
19
#include <cmath>
20
#include <cstddef>
21
#include <cstdio>
22
#include <cstdlib>
23
#include <cstring>
24
#include <fcntl.h>
25
26
#include <algorithm>
27
#include <iostream>
28
#include <limits>
29
#include <string>
30
31
#include "cpl_conv.h"
32
#include "cpl_error.h"
33
#include "cpl_float.h"
34
#include "cpl_json.h"
35
#include "cpl_minixml.h"
36
#include "cpl_multiproc.h"
37
#include "cpl_string.h"
38
#include "cpl_vsi.h"
39
#ifdef EMBED_RESOURCE_FILES
40
#include "embedded_resources.h"
41
#endif
42
#include "gdal_version_full/gdal_version.h"
43
#include "gdal.h"
44
#include "gdal_mdreader.h"
45
#include "gdal_priv.h"
46
#include "gdal_priv_templates.hpp"
47
#include "ogr_core.h"
48
#include "ogr_spatialref.h"
49
#include "ogr_geos.h"
50
51
#include "proj.h"
52
53
#ifdef HAVE_CURL
54
#include "cpl_curl_priv.h"
55
#endif
56
57
static int GetMinBitsForPair(const bool pabSigned[], const bool pabFloating[],
58
                             const int panBits[])
59
25.6k
{
60
25.6k
    if (pabFloating[0] != pabFloating[1])
61
718
    {
62
718
        const int nNotFloatingTypeIndex = pabFloating[0] ? 1 : 0;
63
718
        const int nFloatingTypeIndex = pabFloating[0] ? 0 : 1;
64
65
718
        return std::max(panBits[nFloatingTypeIndex],
66
718
                        2 * panBits[nNotFloatingTypeIndex]);
67
718
    }
68
69
24.9k
    if (pabSigned[0] != pabSigned[1])
70
1.68k
    {
71
1.68k
        if (!pabSigned[0] && panBits[0] < panBits[1])
72
10
            return panBits[1];
73
1.67k
        if (!pabSigned[1] && panBits[1] < panBits[0])
74
1.66k
            return panBits[0];
75
76
7
        const int nUnsignedTypeIndex = pabSigned[0] ? 1 : 0;
77
7
        const int nSignedTypeIndex = pabSigned[0] ? 0 : 1;
78
79
7
        return std::max(panBits[nSignedTypeIndex],
80
7
                        2 * panBits[nUnsignedTypeIndex]);
81
1.67k
    }
82
83
23.2k
    return std::max(panBits[0], panBits[1]);
84
24.9k
}
85
86
static int GetNonComplexDataTypeElementSizeBits(GDALDataType eDataType)
87
51.2k
{
88
51.2k
    switch (eDataType)
89
51.2k
    {
90
16.7k
        case GDT_UInt8:
91
17.7k
        case GDT_Int8:
92
17.7k
            return 8;
93
94
7.43k
        case GDT_UInt16:
95
17.7k
        case GDT_Int16:
96
17.7k
        case GDT_Float16:
97
17.7k
        case GDT_CInt16:
98
17.7k
        case GDT_CFloat16:
99
17.7k
            return 16;
100
101
2.50k
        case GDT_UInt32:
102
10.2k
        case GDT_Int32:
103
11.8k
        case GDT_Float32:
104
11.8k
        case GDT_CInt32:
105
11.8k
        case GDT_CFloat32:
106
11.8k
            return 32;
107
108
3.64k
        case GDT_Float64:
109
3.64k
        case GDT_CFloat64:
110
3.82k
        case GDT_UInt64:
111
3.89k
        case GDT_Int64:
112
3.89k
            return 64;
113
114
0
        case GDT_Unknown:
115
0
        case GDT_TypeCount:
116
0
            break;
117
51.2k
    }
118
0
    return 0;
119
51.2k
}
120
121
/************************************************************************/
122
/*                         GDALDataTypeUnion()                          */
123
/************************************************************************/
124
125
/**
126
 * \brief Return the smallest data type that can fully express both input data
127
 * types.
128
 *
129
 * @param eType1 first data type.
130
 * @param eType2 second data type.
131
 *
132
 * @return a data type able to express eType1 and eType2.
133
 */
134
135
GDALDataType CPL_STDCALL GDALDataTypeUnion(GDALDataType eType1,
136
                                           GDALDataType eType2)
137
138
25.6k
{
139
25.6k
    if (eType1 == GDT_Unknown)
140
6
        return eType2;
141
25.6k
    if (eType2 == GDT_Unknown)
142
0
        return eType1;
143
144
25.6k
    const int panBits[] = {GetNonComplexDataTypeElementSizeBits(eType1),
145
25.6k
                           GetNonComplexDataTypeElementSizeBits(eType2)};
146
147
25.6k
    if (panBits[0] == 0 || panBits[1] == 0)
148
0
        return GDT_Unknown;
149
150
25.6k
    const bool pabSigned[] = {CPL_TO_BOOL(GDALDataTypeIsSigned(eType1)),
151
25.6k
                              CPL_TO_BOOL(GDALDataTypeIsSigned(eType2))};
152
153
25.6k
    const bool bSigned = pabSigned[0] || pabSigned[1];
154
25.6k
    const bool pabFloating[] = {CPL_TO_BOOL(GDALDataTypeIsFloating(eType1)),
155
25.6k
                                CPL_TO_BOOL(GDALDataTypeIsFloating(eType2))};
156
25.6k
    const bool bFloating = pabFloating[0] || pabFloating[1];
157
25.6k
    const int nBits = GetMinBitsForPair(pabSigned, pabFloating, panBits);
158
25.6k
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eType1)) ||
159
25.6k
                            CPL_TO_BOOL(GDALDataTypeIsComplex(eType2));
160
161
25.6k
    return GDALFindDataType(nBits, bSigned, bFloating, bIsComplex);
162
25.6k
}
163
164
/************************************************************************/
165
/*                     GDALDataTypeUnionWithValue()                     */
166
/************************************************************************/
167
168
/**
169
 * \brief Union a data type with the one found for a value
170
 *
171
 * @param eDT the first data type
172
 * @param dfValue the value for which to find a data type and union with eDT
173
 * @param bComplex if the value is complex
174
 *
175
 * @return a data type able to express eDT and dfValue.
176
 */
177
GDALDataType CPL_STDCALL GDALDataTypeUnionWithValue(GDALDataType eDT,
178
                                                    double dfValue,
179
                                                    int bComplex)
180
4
{
181
4
    if (!bComplex && !GDALDataTypeIsComplex(eDT) && eDT != GDT_Unknown)
182
4
    {
183
        // Do not return `GDT_Float16` because that type is not supported everywhere
184
4
        const auto eDTMod = eDT == GDT_Float16 ? GDT_Float32 : eDT;
185
4
        if (GDALIsValueExactAs(dfValue, eDTMod))
186
4
        {
187
4
            return eDTMod;
188
4
        }
189
4
    }
190
191
0
    const GDALDataType eDT2 = GDALFindDataTypeForValue(dfValue, bComplex);
192
0
    return GDALDataTypeUnion(eDT, eDT2);
193
4
}
194
195
/************************************************************************/
196
/*                         GetMinBitsForValue()                         */
197
/************************************************************************/
198
static int GetMinBitsForValue(double dValue)
199
0
{
200
0
    if (round(dValue) == dValue)
201
0
    {
202
0
        if (dValue <= cpl::NumericLimits<GByte>::max() &&
203
0
            dValue >= cpl::NumericLimits<GByte>::lowest())
204
0
            return 8;
205
206
0
        if (dValue <= cpl::NumericLimits<GInt8>::max() &&
207
0
            dValue >= cpl::NumericLimits<GInt8>::lowest())
208
0
            return 8;
209
210
0
        if (dValue <= cpl::NumericLimits<GInt16>::max() &&
211
0
            dValue >= cpl::NumericLimits<GInt16>::lowest())
212
0
            return 16;
213
214
0
        if (dValue <= cpl::NumericLimits<GUInt16>::max() &&
215
0
            dValue >= cpl::NumericLimits<GUInt16>::lowest())
216
0
            return 16;
217
218
0
        if (dValue <= cpl::NumericLimits<GInt32>::max() &&
219
0
            dValue >= cpl::NumericLimits<GInt32>::lowest())
220
0
            return 32;
221
222
0
        if (dValue <= cpl::NumericLimits<GUInt32>::max() &&
223
0
            dValue >= cpl::NumericLimits<GUInt32>::lowest())
224
0
            return 32;
225
226
0
        if (dValue <=
227
0
                static_cast<double>(cpl::NumericLimits<std::uint64_t>::max()) &&
228
0
            dValue >= static_cast<double>(
229
0
                          cpl::NumericLimits<std::uint64_t>::lowest()))
230
0
            return 64;
231
0
    }
232
0
    else if (static_cast<float>(dValue) == dValue)
233
0
    {
234
0
        return 32;
235
0
    }
236
237
0
    return 64;
238
0
}
239
240
/************************************************************************/
241
/*                          GDALFindDataType()                          */
242
/************************************************************************/
243
244
/**
245
 * \brief Finds the smallest data type able to support the given
246
 *  requirements
247
 *
248
 * @param nBits number of bits necessary
249
 * @param bSigned if negative values are necessary
250
 * @param bFloating if non-integer values necessary
251
 * @param bComplex if complex values are necessary
252
 *
253
 * @return a best fit GDALDataType for supporting the requirements
254
 */
255
GDALDataType CPL_STDCALL GDALFindDataType(int nBits, int bSigned, int bFloating,
256
                                          int bComplex)
257
25.6k
{
258
25.6k
    if (!bFloating)
259
22.6k
    {
260
22.6k
        if (!bComplex)
261
22.6k
        {
262
22.6k
            if (!bSigned)
263
12.2k
            {
264
12.2k
                if (nBits <= 8)
265
6.74k
                    return GDT_UInt8;
266
5.48k
                if (nBits <= 16)
267
4.10k
                    return GDT_UInt16;
268
1.38k
                if (nBits <= 32)
269
1.28k
                    return GDT_UInt32;
270
95
                if (nBits <= 64)
271
95
                    return GDT_UInt64;
272
0
                return GDT_Float64;
273
95
            }
274
10.4k
            else  // bSigned
275
10.4k
            {
276
10.4k
                if (nBits <= 8)
277
382
                    return GDT_Int8;
278
10.0k
                if (nBits <= 16)
279
5.34k
                    return GDT_Int16;
280
4.69k
                if (nBits <= 32)
281
4.65k
                    return GDT_Int32;
282
44
                if (nBits <= 64)
283
44
                    return GDT_Int64;
284
0
                return GDT_Float64;
285
44
            }
286
22.6k
        }
287
0
        else  // bComplex
288
0
        {
289
0
            if (!bSigned)
290
0
            {
291
                // We don't have complex unsigned data types, so
292
                // return a large-enough complex signed type
293
294
                // Do not choose CInt16 for backward compatibility
295
                // if (nBits <= 15)
296
                //     return GDT_CInt16;
297
0
                if (nBits <= 31)
298
0
                    return GDT_CInt32;
299
0
                return GDT_CFloat64;
300
0
            }
301
0
            else  // bSigned
302
0
            {
303
0
                if (nBits <= 16)
304
0
                    return GDT_CInt16;
305
0
                if (nBits <= 32)
306
0
                    return GDT_CInt32;
307
0
                return GDT_CFloat64;
308
0
            }
309
0
        }
310
22.6k
    }
311
2.99k
    else  // bFloating
312
2.99k
    {
313
2.99k
        if (!bComplex)
314
2.99k
        {
315
            // Do not choose Float16 since is not supported everywhere
316
            // if (nBits <= 16)
317
            //     return GDT_Float16;
318
2.99k
            if (nBits <= 32)
319
955
                return GDT_Float32;
320
2.04k
            return GDT_Float64;
321
2.99k
        }
322
0
        else  // bComplex
323
0
        {
324
            // Do not choose Float16 since is not supported everywhere
325
            // if (nBits <= 16)
326
            //     return GDT_CFloat16;
327
0
            if (nBits <= 32)
328
0
                return GDT_CFloat32;
329
0
            return GDT_CFloat64;
330
0
        }
331
2.99k
    }
332
25.6k
}
333
334
/************************************************************************/
335
/*                      GDALFindDataTypeForValue()                      */
336
/************************************************************************/
337
338
/**
339
 * \brief Finds the smallest data type able to support the provided value
340
 *
341
 * @param dValue value to support
342
 * @param bComplex is the value complex
343
 *
344
 * @return a best fit GDALDataType for supporting the value
345
 */
346
GDALDataType CPL_STDCALL GDALFindDataTypeForValue(double dValue, int bComplex)
347
0
{
348
0
    const bool bFloating =
349
0
        round(dValue) != dValue ||
350
0
        dValue >
351
0
            static_cast<double>(cpl::NumericLimits<std::uint64_t>::max()) ||
352
0
        dValue <
353
0
            static_cast<double>(cpl::NumericLimits<std::int64_t>::lowest());
354
0
    const bool bSigned = bFloating || dValue < 0;
355
0
    const int nBits = GetMinBitsForValue(dValue);
356
357
0
    return GDALFindDataType(nBits, bSigned, bFloating, bComplex);
358
0
}
359
360
/************************************************************************/
361
/*                      GDALGetDataTypeSizeBytes()                      */
362
/************************************************************************/
363
364
/**
365
 * \brief Get data type size in <b>bytes</b>.
366
 *
367
 * Returns the size of a GDT_* type in bytes.  In contrast,
368
 * GDALGetDataTypeSize() returns the size in <b>bits</b>.
369
 *
370
 * @param eDataType type, such as GDT_UInt8.
371
 * @return the number of bytes or zero if it is not recognised.
372
 */
373
374
int CPL_STDCALL GDALGetDataTypeSizeBytes(GDALDataType eDataType)
375
376
447M
{
377
447M
    switch (eDataType)
378
447M
    {
379
138M
        case GDT_UInt8:
380
141M
        case GDT_Int8:
381
141M
            return 1;
382
383
43.6M
        case GDT_UInt16:
384
61.1M
        case GDT_Int16:
385
61.8M
        case GDT_Float16:
386
61.8M
            return 2;
387
388
10.0M
        case GDT_UInt32:
389
111M
        case GDT_Int32:
390
155M
        case GDT_Float32:
391
155M
        case GDT_CInt16:
392
155M
        case GDT_CFloat16:
393
155M
            return 4;
394
395
83.3M
        case GDT_Float64:
396
83.7M
        case GDT_CInt32:
397
84.1M
        case GDT_CFloat32:
398
86.4M
        case GDT_UInt64:
399
87.6M
        case GDT_Int64:
400
87.6M
            return 8;
401
402
451k
        case GDT_CFloat64:
403
451k
            return 16;
404
405
39.2k
        case GDT_Unknown:
406
39.2k
        case GDT_TypeCount:
407
39.2k
            break;
408
447M
    }
409
39.2k
    return 0;
410
447M
}
411
412
/************************************************************************/
413
/*                      GDALGetDataTypeSizeBits()                       */
414
/************************************************************************/
415
416
/**
417
 * \brief Get data type size in <b>bits</b>.
418
 *
419
 * Returns the size of a GDT_* type in bits, <b>not bytes</b>!  Use
420
 * GDALGetDataTypeSizeBytes() for bytes.
421
 *
422
 * @param eDataType type, such as GDT_UInt8.
423
 * @return the number of bits or zero if it is not recognised.
424
 */
425
426
int CPL_STDCALL GDALGetDataTypeSizeBits(GDALDataType eDataType)
427
428
1.83M
{
429
1.83M
    return GDALGetDataTypeSizeBytes(eDataType) * 8;
430
1.83M
}
431
432
/************************************************************************/
433
/*                        GDALGetDataTypeSize()                         */
434
/************************************************************************/
435
436
/**
437
 * \brief Get data type size in bits.  <b>Deprecated</b>.
438
 *
439
 * Returns the size of a GDT_* type in bits, <b>not bytes</b>!
440
 *
441
 * Use GDALGetDataTypeSizeBytes() for bytes.
442
 * Use GDALGetDataTypeSizeBits() for bits.
443
 *
444
 * @param eDataType type, such as GDT_UInt8.
445
 * @return the number of bits or zero if it is not recognised.
446
 */
447
448
int CPL_STDCALL GDALGetDataTypeSize(GDALDataType eDataType)
449
450
0
{
451
0
    return GDALGetDataTypeSizeBytes(eDataType) * 8;
452
0
}
453
454
/************************************************************************/
455
/*                       GDALDataTypeIsComplex()                        */
456
/************************************************************************/
457
458
/**
459
 * \brief Is data type complex?
460
 *
461
 * @return TRUE if the passed type is complex (one of GDT_CInt16, GDT_CInt32,
462
 * GDT_CFloat32 or GDT_CFloat64), that is it consists of a real and imaginary
463
 * component.
464
 */
465
466
int CPL_STDCALL GDALDataTypeIsComplex(GDALDataType eDataType)
467
468
2.78M
{
469
2.78M
    switch (eDataType)
470
2.78M
    {
471
2.35k
        case GDT_CInt16:
472
3.16k
        case GDT_CInt32:
473
3.63k
        case GDT_CFloat16:
474
6.75k
        case GDT_CFloat32:
475
8.21k
        case GDT_CFloat64:
476
8.21k
            return TRUE;
477
478
550k
        case GDT_UInt8:
479
579k
        case GDT_Int8:
480
1.14M
        case GDT_Int16:
481
1.70M
        case GDT_UInt16:
482
1.80M
        case GDT_Int32:
483
2.33M
        case GDT_UInt32:
484
2.34M
        case GDT_Int64:
485
2.35M
        case GDT_UInt64:
486
2.35M
        case GDT_Float16:
487
2.54M
        case GDT_Float32:
488
2.77M
        case GDT_Float64:
489
2.77M
            return FALSE;
490
491
0
        case GDT_Unknown:
492
0
        case GDT_TypeCount:
493
0
            break;
494
2.78M
    }
495
0
    return FALSE;
496
2.78M
}
497
498
/************************************************************************/
499
/*                       GDALDataTypeIsFloating()                       */
500
/************************************************************************/
501
502
/**
503
 * \brief Is data type floating? (might be complex)
504
 *
505
 * @return TRUE if the passed type is floating (one of GDT_Float32, GDT_Float16,
506
 * GDT_Float64, GDT_CFloat16, GDT_CFloat32, GDT_CFloat64)
507
 */
508
509
int CPL_STDCALL GDALDataTypeIsFloating(GDALDataType eDataType)
510
864k
{
511
864k
    switch (eDataType)
512
864k
    {
513
4
        case GDT_Float16:
514
82.6k
        case GDT_Float32:
515
215k
        case GDT_Float64:
516
215k
        case GDT_CFloat16:
517
215k
        case GDT_CFloat32:
518
215k
        case GDT_CFloat64:
519
215k
            return TRUE;
520
521
185k
        case GDT_UInt8:
522
190k
        case GDT_Int8:
523
223k
        case GDT_Int16:
524
339k
        case GDT_UInt16:
525
398k
        case GDT_Int32:
526
647k
        case GDT_UInt32:
527
649k
        case GDT_Int64:
528
649k
        case GDT_UInt64:
529
649k
        case GDT_CInt16:
530
649k
        case GDT_CInt32:
531
649k
            return FALSE;
532
533
0
        case GDT_Unknown:
534
0
        case GDT_TypeCount:
535
0
            break;
536
864k
    }
537
0
    return FALSE;
538
864k
}
539
540
/************************************************************************/
541
/*                       GDALDataTypeIsInteger()                        */
542
/************************************************************************/
543
544
/**
545
 * \brief Is data type integer? (might be complex)
546
 *
547
 * @return TRUE if the passed type is integer (one of GDT_UInt8, GDT_Int16,
548
 * GDT_UInt16, GDT_Int32, GDT_UInt32, GDT_CInt16, GDT_CInt32).
549
 */
550
551
int CPL_STDCALL GDALDataTypeIsInteger(GDALDataType eDataType)
552
553
899k
{
554
899k
    switch (eDataType)
555
899k
    {
556
188k
        case GDT_UInt8:
557
193k
        case GDT_Int8:
558
235k
        case GDT_Int16:
559
398k
        case GDT_UInt16:
560
454k
        case GDT_Int32:
561
824k
        case GDT_UInt32:
562
824k
        case GDT_CInt16:
563
824k
        case GDT_CInt32:
564
824k
        case GDT_UInt64:
565
825k
        case GDT_Int64:
566
825k
            return TRUE;
567
568
86
        case GDT_Float16:
569
48.5k
        case GDT_Float32:
570
73.2k
        case GDT_Float64:
571
73.2k
        case GDT_CFloat16:
572
73.2k
        case GDT_CFloat32:
573
73.2k
        case GDT_CFloat64:
574
73.2k
            return FALSE;
575
576
0
        case GDT_Unknown:
577
0
        case GDT_TypeCount:
578
0
            break;
579
899k
    }
580
0
    return FALSE;
581
899k
}
582
583
/************************************************************************/
584
/*                        GDALDataTypeIsSigned()                        */
585
/************************************************************************/
586
587
/**
588
 * \brief Is data type signed?
589
 *
590
 * @return TRUE if the passed type is signed.
591
 */
592
593
int CPL_STDCALL GDALDataTypeIsSigned(GDALDataType eDataType)
594
1.25M
{
595
1.25M
    switch (eDataType)
596
1.25M
    {
597
352k
        case GDT_UInt8:
598
575k
        case GDT_UInt16:
599
1.07M
        case GDT_UInt32:
600
1.07M
        case GDT_UInt64:
601
1.07M
            return FALSE;
602
603
9.95k
        case GDT_Int8:
604
66.0k
        case GDT_Int16:
605
175k
        case GDT_Int32:
606
177k
        case GDT_Int64:
607
177k
        case GDT_Float16:
608
179k
        case GDT_Float32:
609
183k
        case GDT_Float64:
610
183k
        case GDT_CInt16:
611
183k
        case GDT_CInt32:
612
183k
        case GDT_CFloat16:
613
183k
        case GDT_CFloat32:
614
183k
        case GDT_CFloat64:
615
183k
            return TRUE;
616
617
0
        case GDT_Unknown:
618
0
        case GDT_TypeCount:
619
0
            break;
620
1.25M
    }
621
0
    return FALSE;
622
1.25M
}
623
624
/************************************************************************/
625
/*                   GDALDataTypeIsConversionLossy()                    */
626
/************************************************************************/
627
628
/**
629
 * \brief Is conversion from eTypeFrom to eTypeTo potentially lossy
630
 *
631
 * @param eTypeFrom input datatype
632
 * @param eTypeTo output datatype
633
 * @return TRUE if conversion from eTypeFrom to eTypeTo potentially lossy.
634
 */
635
636
int CPL_STDCALL GDALDataTypeIsConversionLossy(GDALDataType eTypeFrom,
637
                                              GDALDataType eTypeTo)
638
876k
{
639
    // E.g cfloat32 -> float32
640
876k
    if (GDALDataTypeIsComplex(eTypeFrom) && !GDALDataTypeIsComplex(eTypeTo))
641
18
        return TRUE;
642
643
876k
    eTypeFrom = GDALGetNonComplexDataType(eTypeFrom);
644
876k
    eTypeTo = GDALGetNonComplexDataType(eTypeTo);
645
646
876k
    if (GDALDataTypeIsInteger(eTypeTo))
647
812k
    {
648
        // E.g. float32 -> int32
649
812k
        if (GDALDataTypeIsFloating(eTypeFrom))
650
210k
            return TRUE;
651
652
        // E.g. Int16 to UInt16
653
602k
        const int bIsFromSigned = GDALDataTypeIsSigned(eTypeFrom);
654
602k
        const int bIsToSigned = GDALDataTypeIsSigned(eTypeTo);
655
602k
        if (bIsFromSigned && !bIsToSigned)
656
933
            return TRUE;
657
658
        // E.g UInt32 to UInt16
659
601k
        const int nFromSize = GDALGetDataTypeSizeBits(eTypeFrom);
660
601k
        const int nToSize = GDALGetDataTypeSizeBits(eTypeTo);
661
601k
        if (nFromSize > nToSize)
662
996
            return TRUE;
663
664
        // E.g UInt16 to Int16
665
600k
        if (nFromSize == nToSize && !bIsFromSigned && bIsToSigned)
666
0
            return TRUE;
667
668
600k
        return FALSE;
669
600k
    }
670
671
64.6k
    if (eTypeTo == GDT_Float16 &&
672
86
        (eTypeFrom == GDT_Int16 || eTypeFrom == GDT_UInt16 ||
673
86
         eTypeFrom == GDT_Int32 || eTypeFrom == GDT_UInt32 ||
674
86
         eTypeFrom == GDT_Int64 || eTypeFrom == GDT_UInt64 ||
675
86
         eTypeFrom == GDT_Float32 || eTypeFrom == GDT_Float64))
676
6
    {
677
6
        return TRUE;
678
6
    }
679
680
64.6k
    if (eTypeTo == GDT_Float32 &&
681
42.5k
        (eTypeFrom == GDT_Int32 || eTypeFrom == GDT_UInt32 ||
682
42.5k
         eTypeFrom == GDT_Int64 || eTypeFrom == GDT_UInt64 ||
683
42.5k
         eTypeFrom == GDT_Float64))
684
0
    {
685
0
        return TRUE;
686
0
    }
687
688
64.6k
    if (eTypeTo == GDT_Float64 &&
689
21.9k
        (eTypeFrom == GDT_Int64 || eTypeFrom == GDT_UInt64))
690
0
    {
691
0
        return TRUE;
692
0
    }
693
694
64.6k
    return FALSE;
695
64.6k
}
696
697
/************************************************************************/
698
/*                        GDALGetDataTypeName()                         */
699
/************************************************************************/
700
701
/**
702
 * \brief Get name of data type.
703
 *
704
 * Returns a symbolic name for the data type.  This is essentially the
705
 * the enumerated item name with the GDT_ prefix removed.  So GDT_UInt8 returns
706
 * "Byte".  The returned strings are static strings and should not be modified
707
 * or freed by the application.  These strings are useful for reporting
708
 * datatypes in debug statements, errors and other user output.
709
 *
710
 * @param eDataType type to get name of.
711
 * @return string corresponding to existing data type
712
 *         or NULL pointer if invalid type given.
713
 */
714
715
const char *CPL_STDCALL GDALGetDataTypeName(GDALDataType eDataType)
716
717
2.39M
{
718
2.39M
    switch (eDataType)
719
2.39M
    {
720
8.33k
        case GDT_Unknown:
721
8.33k
            return "Unknown";
722
723
1.58M
        case GDT_UInt8:
724
            // TODO: return UInt8 for GDAL 4 ?
725
1.58M
            return "Byte";
726
727
3.40k
        case GDT_Int8:
728
3.40k
            return "Int8";
729
730
172k
        case GDT_UInt16:
731
172k
            return "UInt16";
732
733
251k
        case GDT_Int16:
734
251k
            return "Int16";
735
736
30.6k
        case GDT_UInt32:
737
30.6k
            return "UInt32";
738
739
29.5k
        case GDT_Int32:
740
29.5k
            return "Int32";
741
742
3.44k
        case GDT_UInt64:
743
3.44k
            return "UInt64";
744
745
2.00k
        case GDT_Int64:
746
2.00k
            return "Int64";
747
748
95
        case GDT_Float16:
749
95
            return "Float16";
750
751
274k
        case GDT_Float32:
752
274k
            return "Float32";
753
754
16.1k
        case GDT_Float64:
755
16.1k
            return "Float64";
756
757
4.66k
        case GDT_CInt16:
758
4.66k
            return "CInt16";
759
760
2.05k
        case GDT_CInt32:
761
2.05k
            return "CInt32";
762
763
94
        case GDT_CFloat16:
764
94
            return "CFloat16";
765
766
5.17k
        case GDT_CFloat32:
767
5.17k
            return "CFloat32";
768
769
1.33k
        case GDT_CFloat64:
770
1.33k
            return "CFloat64";
771
772
0
        case GDT_TypeCount:
773
0
            break;
774
2.39M
    }
775
0
    return nullptr;
776
2.39M
}
777
778
/************************************************************************/
779
/*                       GDALGetDataTypeByName()                        */
780
/************************************************************************/
781
782
/**
783
 * \brief Get data type by symbolic name.
784
 *
785
 * Returns a data type corresponding to the given symbolic name. This
786
 * function is opposite to the GDALGetDataTypeName().
787
 *
788
 * @param pszName string containing the symbolic name of the type.
789
 *
790
 * @return GDAL data type.
791
 */
792
793
GDALDataType CPL_STDCALL GDALGetDataTypeByName(const char *pszName)
794
795
81.1k
{
796
81.1k
    VALIDATE_POINTER1(pszName, "GDALGetDataTypeByName", GDT_Unknown);
797
798
81.1k
    if (EQUAL(pszName, "UInt8"))
799
0
        return GDT_UInt8;
800
801
183k
    for (int iType = 1; iType < GDT_TypeCount; iType++)
802
183k
    {
803
183k
        const auto eType = static_cast<GDALDataType>(iType);
804
183k
        if (GDALGetDataTypeName(eType) != nullptr &&
805
183k
            EQUAL(GDALGetDataTypeName(eType), pszName))
806
81.1k
        {
807
81.1k
            return eType;
808
81.1k
        }
809
183k
    }
810
811
46
    return GDT_Unknown;
812
81.1k
}
813
814
/************************************************************************/
815
/*                     GDALAdjustValueToDataType()                      */
816
/************************************************************************/
817
818
template <class T>
819
static inline void ClampAndRound(double &dfValue, bool &bClamped,
820
                                 bool &bRounded)
821
0
{
822
0
    if (dfValue < static_cast<double>(cpl::NumericLimits<T>::lowest()))
823
0
    {
824
0
        bClamped = true;
825
0
        dfValue = static_cast<double>(cpl::NumericLimits<T>::lowest());
826
0
    }
827
0
    else if (dfValue > static_cast<double>(cpl::NumericLimits<T>::max()))
828
0
    {
829
0
        bClamped = true;
830
0
        dfValue = static_cast<double>(cpl::NumericLimits<T>::max());
831
0
    }
832
0
    else if (dfValue != static_cast<double>(static_cast<T>(dfValue)))
833
0
    {
834
0
        bRounded = true;
835
0
        dfValue = static_cast<double>(static_cast<T>(floor(dfValue + 0.5)));
836
0
    }
837
0
}
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<unsigned char>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<signed char>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<short>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<unsigned short>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<int>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<unsigned int>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<long>(double&, bool&, bool&)
Unexecuted instantiation: gdal_misc.cpp:void ClampAndRound<unsigned long>(double&, bool&, bool&)
838
839
/**
840
 * \brief Adjust a value to the output data type
841
 *
842
 * Adjustment consist in clamping to minimum/maximum values of the data type
843
 * and rounding for integral types.
844
 *
845
 * @param eDT target data type.
846
 * @param dfValue value to adjust.
847
 * @param pbClamped pointer to a integer(boolean) to indicate if clamping has
848
 * been made, or NULL
849
 * @param pbRounded pointer to a integer(boolean) to indicate if rounding has
850
 * been made, or NULL
851
 *
852
 * @return adjusted value
853
 */
854
855
double GDALAdjustValueToDataType(GDALDataType eDT, double dfValue,
856
                                 int *pbClamped, int *pbRounded)
857
0
{
858
0
    bool bClamped = false;
859
0
    bool bRounded = false;
860
0
    switch (eDT)
861
0
    {
862
0
        case GDT_UInt8:
863
0
            ClampAndRound<GByte>(dfValue, bClamped, bRounded);
864
0
            break;
865
0
        case GDT_Int8:
866
0
            ClampAndRound<GInt8>(dfValue, bClamped, bRounded);
867
0
            break;
868
0
        case GDT_Int16:
869
0
            ClampAndRound<GInt16>(dfValue, bClamped, bRounded);
870
0
            break;
871
0
        case GDT_UInt16:
872
0
            ClampAndRound<GUInt16>(dfValue, bClamped, bRounded);
873
0
            break;
874
0
        case GDT_Int32:
875
0
            ClampAndRound<GInt32>(dfValue, bClamped, bRounded);
876
0
            break;
877
0
        case GDT_UInt32:
878
0
            ClampAndRound<GUInt32>(dfValue, bClamped, bRounded);
879
0
            break;
880
0
        case GDT_Int64:
881
0
            ClampAndRound<std::int64_t>(dfValue, bClamped, bRounded);
882
0
            break;
883
0
        case GDT_UInt64:
884
0
            ClampAndRound<std::uint64_t>(dfValue, bClamped, bRounded);
885
0
            break;
886
0
        case GDT_Float16:
887
0
        {
888
0
            if (!std::isfinite(dfValue))
889
0
                break;
890
891
            // TODO: Use ClampAndRound
892
0
            if (dfValue < cpl::NumericLimits<GFloat16>::lowest())
893
0
            {
894
0
                bClamped = TRUE;
895
0
                dfValue =
896
0
                    static_cast<double>(cpl::NumericLimits<GFloat16>::lowest());
897
0
            }
898
0
            else if (dfValue > cpl::NumericLimits<GFloat16>::max())
899
0
            {
900
0
                bClamped = TRUE;
901
0
                dfValue =
902
0
                    static_cast<double>(cpl::NumericLimits<GFloat16>::max());
903
0
            }
904
0
            else
905
0
            {
906
                // Intentionally lose precision.
907
                // TODO(schwehr): Is the double cast really necessary?
908
                // If so, why?  What will fail?
909
0
                dfValue = static_cast<double>(static_cast<GFloat16>(dfValue));
910
0
            }
911
0
            break;
912
0
        }
913
0
        case GDT_Float32:
914
0
        {
915
0
            if (!std::isfinite(dfValue))
916
0
                break;
917
918
            // TODO: Use ClampAndRound
919
0
            if (dfValue < cpl::NumericLimits<float>::lowest())
920
0
            {
921
0
                bClamped = TRUE;
922
0
                dfValue =
923
0
                    static_cast<double>(cpl::NumericLimits<float>::lowest());
924
0
            }
925
0
            else if (dfValue > cpl::NumericLimits<float>::max())
926
0
            {
927
0
                bClamped = TRUE;
928
0
                dfValue = static_cast<double>(cpl::NumericLimits<float>::max());
929
0
            }
930
0
            else
931
0
            {
932
                // Intentionally lose precision.
933
                // TODO(schwehr): Is the double cast really necessary?
934
                // If so, why?  What will fail?
935
0
                dfValue = static_cast<double>(static_cast<float>(dfValue));
936
0
            }
937
0
            break;
938
0
        }
939
0
        case GDT_Float64:
940
0
        case GDT_CInt16:
941
0
        case GDT_CInt32:
942
0
        case GDT_CFloat16:
943
0
        case GDT_CFloat32:
944
0
        case GDT_CFloat64:
945
0
        case GDT_Unknown:
946
0
        case GDT_TypeCount:
947
0
            break;
948
0
    }
949
0
    if (pbClamped)
950
0
        *pbClamped = bClamped;
951
0
    if (pbRounded)
952
0
        *pbRounded = bRounded;
953
0
    return dfValue;
954
0
}
955
956
/************************************************************************/
957
/*                         GDALIsValueExactAs()                         */
958
/************************************************************************/
959
960
/**
961
 * \brief Check whether the provided value can be exactly represented in a
962
 * data type.
963
 *
964
 * Only implemented for non-complex data types
965
 *
966
 * @param dfValue value to check.
967
 * @param eDT target data type.
968
 *
969
 * @return true if the provided value can be exactly represented in the
970
 * data type.
971
 * @since GDAL 3.10
972
 */
973
bool GDALIsValueExactAs(double dfValue, GDALDataType eDT)
974
24.8k
{
975
24.8k
    switch (eDT)
976
24.8k
    {
977
14.4k
        case GDT_UInt8:
978
14.4k
            return GDALIsValueExactAs<uint8_t>(dfValue);
979
892
        case GDT_Int8:
980
892
            return GDALIsValueExactAs<int8_t>(dfValue);
981
4.50k
        case GDT_UInt16:
982
4.50k
            return GDALIsValueExactAs<uint16_t>(dfValue);
983
1.10k
        case GDT_Int16:
984
1.10k
            return GDALIsValueExactAs<int16_t>(dfValue);
985
1.34k
        case GDT_UInt32:
986
1.34k
            return GDALIsValueExactAs<uint32_t>(dfValue);
987
960
        case GDT_Int32:
988
960
            return GDALIsValueExactAs<int32_t>(dfValue);
989
0
        case GDT_UInt64:
990
0
            return GDALIsValueExactAs<uint64_t>(dfValue);
991
0
        case GDT_Int64:
992
0
            return GDALIsValueExactAs<int64_t>(dfValue);
993
0
        case GDT_Float16:
994
0
            return GDALIsValueExactAs<GFloat16>(dfValue);
995
0
        case GDT_Float32:
996
0
            return GDALIsValueExactAs<float>(dfValue);
997
1.63k
        case GDT_Float64:
998
1.63k
            return true;
999
0
        case GDT_Unknown:
1000
0
        case GDT_CInt16:
1001
0
        case GDT_CInt32:
1002
0
        case GDT_CFloat16:
1003
0
        case GDT_CFloat32:
1004
0
        case GDT_CFloat64:
1005
0
        case GDT_TypeCount:
1006
0
            break;
1007
24.8k
    }
1008
0
    return true;
1009
24.8k
}
1010
1011
/************************************************************************/
1012
/*                        GDALIsValueInRangeOf()                        */
1013
/************************************************************************/
1014
1015
/**
1016
 * \brief Check whether the provided value can be represented in the range
1017
 * of the data type, possibly with rounding.
1018
 *
1019
 * Only implemented for non-complex data types
1020
 *
1021
 * @param dfValue value to check.
1022
 * @param eDT target data type.
1023
 *
1024
 * @return true if the provided value can be represented in the range
1025
 * of the data type, possibly with rounding.
1026
 * @since GDAL 3.11
1027
 */
1028
bool GDALIsValueInRangeOf(double dfValue, GDALDataType eDT)
1029
0
{
1030
0
    switch (eDT)
1031
0
    {
1032
0
        case GDT_UInt8:
1033
0
            return GDALIsValueInRange<uint8_t>(dfValue);
1034
0
        case GDT_Int8:
1035
0
            return GDALIsValueInRange<int8_t>(dfValue);
1036
0
        case GDT_UInt16:
1037
0
            return GDALIsValueInRange<uint16_t>(dfValue);
1038
0
        case GDT_Int16:
1039
0
            return GDALIsValueInRange<int16_t>(dfValue);
1040
0
        case GDT_UInt32:
1041
0
            return GDALIsValueInRange<uint32_t>(dfValue);
1042
0
        case GDT_Int32:
1043
0
            return GDALIsValueInRange<int32_t>(dfValue);
1044
0
        case GDT_UInt64:
1045
0
            return GDALIsValueInRange<uint64_t>(dfValue);
1046
0
        case GDT_Int64:
1047
0
            return GDALIsValueInRange<int64_t>(dfValue);
1048
0
        case GDT_Float16:
1049
0
            return GDALIsValueInRange<GFloat16>(dfValue);
1050
0
        case GDT_Float32:
1051
0
            return GDALIsValueInRange<float>(dfValue);
1052
0
        case GDT_Float64:
1053
0
            return true;
1054
0
        case GDT_Unknown:
1055
0
        case GDT_CInt16:
1056
0
        case GDT_CInt32:
1057
0
        case GDT_CFloat16:
1058
0
        case GDT_CFloat32:
1059
0
        case GDT_CFloat64:
1060
0
        case GDT_TypeCount:
1061
0
            break;
1062
0
    }
1063
0
    return true;
1064
0
}
1065
1066
/************************************************************************/
1067
/*                     GDALGetNonComplexDataType()                      */
1068
/************************************************************************/
1069
/**
1070
 * \brief Return the base data type for the specified input.
1071
 *
1072
 * If the input data type is complex this function returns the base type
1073
 * i.e. the data type of the real and imaginary parts (non-complex).
1074
 * If the input data type is already non-complex, then it is returned
1075
 * unchanged.
1076
 *
1077
 * @param eDataType type, such as GDT_CFloat32.
1078
 *
1079
 * @return GDAL data type.
1080
 */
1081
GDALDataType CPL_STDCALL GDALGetNonComplexDataType(GDALDataType eDataType)
1082
1.75M
{
1083
1.75M
    switch (eDataType)
1084
1.75M
    {
1085
2
        case GDT_CInt16:
1086
2
            return GDT_Int16;
1087
1
        case GDT_CInt32:
1088
1
            return GDT_Int32;
1089
6
        case GDT_CFloat16:
1090
6
            return GDT_Float16;
1091
11
        case GDT_CFloat32:
1092
11
            return GDT_Float32;
1093
0
        case GDT_CFloat64:
1094
0
            return GDT_Float64;
1095
1096
354k
        case GDT_UInt8:
1097
624k
        case GDT_UInt16:
1098
1.24M
        case GDT_UInt32:
1099
1.24M
        case GDT_UInt64:
1100
1.25M
        case GDT_Int8:
1101
1.30M
        case GDT_Int16:
1102
1.41M
        case GDT_Int32:
1103
1.41M
        case GDT_Int64:
1104
1.41M
        case GDT_Float16:
1105
1.58M
        case GDT_Float32:
1106
1.75M
        case GDT_Float64:
1107
1.75M
            break;
1108
1109
0
        case GDT_Unknown:
1110
0
        case GDT_TypeCount:
1111
0
            break;
1112
1.75M
    }
1113
1.75M
    return eDataType;
1114
1.75M
}
1115
1116
/************************************************************************/
1117
/*                    GDALGetAsyncStatusTypeByName()                    */
1118
/************************************************************************/
1119
/**
1120
 * Get AsyncStatusType by symbolic name.
1121
 *
1122
 * Returns a data type corresponding to the given symbolic name. This
1123
 * function is opposite to the GDALGetAsyncStatusTypeName().
1124
 *
1125
 * @param pszName string containing the symbolic name of the type.
1126
 *
1127
 * @return GDAL AsyncStatus type.
1128
 */
1129
GDALAsyncStatusType CPL_DLL CPL_STDCALL
1130
GDALGetAsyncStatusTypeByName(const char *pszName)
1131
0
{
1132
0
    VALIDATE_POINTER1(pszName, "GDALGetAsyncStatusTypeByName", GARIO_ERROR);
1133
1134
0
    for (int iType = 0; iType < GARIO_TypeCount; iType++)
1135
0
    {
1136
0
        const auto eType = static_cast<GDALAsyncStatusType>(iType);
1137
0
        if (GDALGetAsyncStatusTypeName(eType) != nullptr &&
1138
0
            EQUAL(GDALGetAsyncStatusTypeName(eType), pszName))
1139
0
        {
1140
0
            return eType;
1141
0
        }
1142
0
    }
1143
1144
0
    return GARIO_ERROR;
1145
0
}
1146
1147
/************************************************************************/
1148
/*                     GDALGetAsyncStatusTypeName()                     */
1149
/************************************************************************/
1150
1151
/**
1152
 * Get name of AsyncStatus data type.
1153
 *
1154
 * Returns a symbolic name for the AsyncStatus data type.  This is essentially
1155
 * the enumerated item name with the GARIO_ prefix removed.  So
1156
 * GARIO_COMPLETE returns "COMPLETE".  The returned strings are static strings
1157
 * and should not be modified or freed by the application.  These strings are
1158
 * useful for reporting datatypes in debug statements, errors and other user
1159
 * output.
1160
 *
1161
 * @param eAsyncStatusType type to get name of.
1162
 * @return string corresponding to type.
1163
 */
1164
1165
const char *CPL_STDCALL
1166
GDALGetAsyncStatusTypeName(GDALAsyncStatusType eAsyncStatusType)
1167
1168
0
{
1169
0
    switch (eAsyncStatusType)
1170
0
    {
1171
0
        case GARIO_PENDING:
1172
0
            return "PENDING";
1173
1174
0
        case GARIO_UPDATE:
1175
0
            return "UPDATE";
1176
1177
0
        case GARIO_ERROR:
1178
0
            return "ERROR";
1179
1180
0
        case GARIO_COMPLETE:
1181
0
            return "COMPLETE";
1182
1183
0
        default:
1184
0
            return nullptr;
1185
0
    }
1186
0
}
1187
1188
/************************************************************************/
1189
/*                  GDALGetPaletteInterpretationName()                  */
1190
/************************************************************************/
1191
1192
/**
1193
 * \brief Get name of palette interpretation
1194
 *
1195
 * Returns a symbolic name for the palette interpretation.  This is the
1196
 * the enumerated item name with the GPI_ prefix removed.  So GPI_Gray returns
1197
 * "Gray".  The returned strings are static strings and should not be modified
1198
 * or freed by the application.
1199
 *
1200
 * @param eInterp palette interpretation to get name of.
1201
 * @return string corresponding to palette interpretation.
1202
 */
1203
1204
const char *GDALGetPaletteInterpretationName(GDALPaletteInterp eInterp)
1205
1206
0
{
1207
0
    switch (eInterp)
1208
0
    {
1209
0
        case GPI_Gray:
1210
0
            return "Gray";
1211
1212
0
        case GPI_RGB:
1213
0
            return "RGB";
1214
1215
0
        case GPI_CMYK:
1216
0
            return "CMYK";
1217
1218
0
        case GPI_HLS:
1219
0
            return "HLS";
1220
1221
0
        default:
1222
0
            return "Unknown";
1223
0
    }
1224
0
}
1225
1226
/************************************************************************/
1227
/*                   GDALGetColorInterpretationName()                   */
1228
/************************************************************************/
1229
1230
/**
1231
 * \brief Get name of color interpretation
1232
 *
1233
 * Returns a symbolic name for the color interpretation.  This is derived from
1234
 * the enumerated item name with the GCI_ prefix removed, but there are some
1235
 * variations. So GCI_GrayIndex returns "Gray" and GCI_RedBand returns "Red".
1236
 * The returned strings are static strings and should not be modified
1237
 * or freed by the application.
1238
 *
1239
 * @param eInterp color interpretation to get name of.
1240
 * @return string corresponding to color interpretation
1241
 *         or NULL pointer if invalid enumerator given.
1242
 */
1243
1244
const char *GDALGetColorInterpretationName(GDALColorInterp eInterp)
1245
1246
362k
{
1247
362k
    static_assert(GCI_IR_Start == GCI_RedEdgeBand + 1);
1248
362k
    static_assert(GCI_NIRBand == GCI_IR_Start);
1249
362k
    static_assert(GCI_SAR_Start == GCI_IR_End + 1);
1250
362k
    static_assert(GCI_Max == GCI_SAR_End);
1251
1252
362k
    switch (eInterp)
1253
362k
    {
1254
33.1k
        case GCI_Undefined:
1255
33.1k
            break;
1256
1257
95.3k
        case GCI_GrayIndex:
1258
95.3k
            return "Gray";
1259
1260
82.2k
        case GCI_PaletteIndex:
1261
82.2k
            return "Palette";
1262
1263
49.0k
        case GCI_RedBand:
1264
49.0k
            return "Red";
1265
1266
5.66k
        case GCI_GreenBand:
1267
5.66k
            return "Green";
1268
1269
5.09k
        case GCI_BlueBand:
1270
5.09k
            return "Blue";
1271
1272
12.1k
        case GCI_AlphaBand:
1273
12.1k
            return "Alpha";
1274
1275
2.43k
        case GCI_HueBand:
1276
2.43k
            return "Hue";
1277
1278
2.43k
        case GCI_SaturationBand:
1279
2.43k
            return "Saturation";
1280
1281
2.43k
        case GCI_LightnessBand:
1282
2.43k
            return "Lightness";
1283
1284
2.43k
        case GCI_CyanBand:
1285
2.43k
            return "Cyan";
1286
1287
2.43k
        case GCI_MagentaBand:
1288
2.43k
            return "Magenta";
1289
1290
2.43k
        case GCI_YellowBand:
1291
2.43k
            return "Yellow";
1292
1293
2.43k
        case GCI_BlackBand:
1294
2.43k
            return "Black";
1295
1296
2.43k
        case GCI_YCbCr_YBand:
1297
2.43k
            return "YCbCr_Y";
1298
1299
2.43k
        case GCI_YCbCr_CbBand:
1300
2.43k
            return "YCbCr_Cb";
1301
1302
2.43k
        case GCI_YCbCr_CrBand:
1303
2.43k
            return "YCbCr_Cr";
1304
1305
2.43k
        case GCI_PanBand:
1306
2.43k
            return "Pan";
1307
1308
2.43k
        case GCI_CoastalBand:
1309
2.43k
            return "Coastal";
1310
1311
2.43k
        case GCI_RedEdgeBand:
1312
2.43k
            return "RedEdge";
1313
1314
2.43k
        case GCI_NIRBand:
1315
2.43k
            return "NIR";
1316
1317
2.43k
        case GCI_SWIRBand:
1318
2.43k
            return "SWIR";
1319
1320
2.43k
        case GCI_MWIRBand:
1321
2.43k
            return "MWIR";
1322
1323
2.43k
        case GCI_LWIRBand:
1324
2.43k
            return "LWIR";
1325
1326
2.43k
        case GCI_TIRBand:
1327
2.43k
            return "TIR";
1328
1329
2.43k
        case GCI_OtherIRBand:
1330
2.43k
            return "OtherIR";
1331
1332
2.43k
        case GCI_IR_Reserved_1:
1333
2.43k
            return "IR_Reserved_1";
1334
1335
2.43k
        case GCI_IR_Reserved_2:
1336
2.43k
            return "IR_Reserved_2";
1337
1338
2.43k
        case GCI_IR_Reserved_3:
1339
2.43k
            return "IR_Reserved_3";
1340
1341
2.43k
        case GCI_IR_Reserved_4:
1342
2.43k
            return "IR_Reserved_4";
1343
1344
2.43k
        case GCI_SAR_Ka_Band:
1345
2.43k
            return "SAR_Ka";
1346
1347
2.43k
        case GCI_SAR_K_Band:
1348
2.43k
            return "SAR_K";
1349
1350
2.43k
        case GCI_SAR_Ku_Band:
1351
2.43k
            return "SAR_Ku";
1352
1353
2.43k
        case GCI_SAR_X_Band:
1354
2.43k
            return "SAR_X";
1355
1356
2.43k
        case GCI_SAR_C_Band:
1357
2.43k
            return "SAR_C";
1358
1359
2.43k
        case GCI_SAR_S_Band:
1360
2.43k
            return "SAR_S";
1361
1362
2.43k
        case GCI_SAR_L_Band:
1363
2.43k
            return "SAR_L";
1364
1365
2.43k
        case GCI_SAR_P_Band:
1366
2.43k
            return "SAR_P";
1367
1368
2.43k
        case GCI_SAR_Reserved_1:
1369
2.43k
            return "SAR_Reserved_1";
1370
1371
2.43k
        case GCI_SAR_Reserved_2:
1372
2.43k
            return "SAR_Reserved_2";
1373
1374
            // If adding any (non-reserved) value, also update GDALGetColorInterpretationList()
1375
362k
    }
1376
33.1k
    return "Undefined";
1377
362k
}
1378
1379
/************************************************************************/
1380
/*                  GDALGetColorInterpretationByName()                  */
1381
/************************************************************************/
1382
1383
/**
1384
 * \brief Get the list of valid color interpretations.
1385
 *
1386
 * Reserved values of the GDALColorInterp enumeration are not listed.
1387
 *
1388
 * @param[out] pnCount Pointer to an integer that will be set to the number of
1389
 *                     values of the returned array. It must not be null.
1390
 *
1391
 * @return array of *pnCount values
1392
 *
1393
 */
1394
const GDALColorInterp *GDALGetColorInterpretationList(int *pnCount)
1395
0
{
1396
0
    VALIDATE_POINTER1(pnCount, "GDALGetColorInterpretationList", nullptr);
1397
1398
0
    static constexpr GDALColorInterp list[] = {
1399
0
        GCI_Undefined,     GCI_GrayIndex,    GCI_PaletteIndex,
1400
0
        GCI_RedBand,       GCI_GreenBand,    GCI_BlueBand,
1401
0
        GCI_AlphaBand,     GCI_HueBand,      GCI_SaturationBand,
1402
0
        GCI_LightnessBand, GCI_CyanBand,     GCI_MagentaBand,
1403
0
        GCI_YellowBand,    GCI_BlackBand,    GCI_YCbCr_YBand,
1404
0
        GCI_YCbCr_CbBand,  GCI_YCbCr_CrBand, GCI_PanBand,
1405
0
        GCI_CoastalBand,   GCI_RedEdgeBand,  GCI_NIRBand,
1406
0
        GCI_SWIRBand,      GCI_MWIRBand,     GCI_LWIRBand,
1407
0
        GCI_TIRBand,       GCI_OtherIRBand,  GCI_SAR_Ka_Band,
1408
0
        GCI_SAR_K_Band,    GCI_SAR_Ku_Band,  GCI_SAR_X_Band,
1409
0
        GCI_SAR_C_Band,    GCI_SAR_S_Band,   GCI_SAR_L_Band,
1410
0
        GCI_SAR_P_Band,
1411
0
    };
1412
0
    *pnCount = static_cast<int>(CPL_ARRAYSIZE(list));
1413
0
    return list;
1414
0
}
1415
1416
/************************************************************************/
1417
/*                  GDALGetColorInterpretationByName()                  */
1418
/************************************************************************/
1419
1420
/**
1421
 * \brief Get color interpretation by symbolic name.
1422
 *
1423
 * Returns a color interpretation corresponding to the given symbolic name. This
1424
 * function is opposite to the GDALGetColorInterpretationName().
1425
 *
1426
 * @param pszName string containing the symbolic name of the color
1427
 * interpretation.
1428
 *
1429
 * @return GDAL color interpretation.
1430
 *
1431
 */
1432
1433
GDALColorInterp GDALGetColorInterpretationByName(const char *pszName)
1434
1435
32.5k
{
1436
32.5k
    VALIDATE_POINTER1(pszName, "GDALGetColorInterpretationByName",
1437
32.5k
                      GCI_Undefined);
1438
1439
215k
    for (int iType = 0; iType <= GCI_Max; iType++)
1440
213k
    {
1441
213k
        if (EQUAL(GDALGetColorInterpretationName(
1442
213k
                      static_cast<GDALColorInterp>(iType)),
1443
213k
                  pszName))
1444
30.1k
        {
1445
30.1k
            return static_cast<GDALColorInterp>(iType);
1446
30.1k
        }
1447
213k
    }
1448
1449
    // Accept British English spelling
1450
2.43k
    if (EQUAL(pszName, "grey"))
1451
29
        return GCI_GrayIndex;
1452
1453
2.40k
    return GCI_Undefined;
1454
2.43k
}
1455
1456
/************************************************************************/
1457
/*                GDALGetColorInterpFromSTACCommonName()                */
1458
/************************************************************************/
1459
1460
static const struct
1461
{
1462
    const char *pszName;
1463
    GDALColorInterp eInterp;
1464
} asSTACCommonNames[] = {
1465
    {"pan", GCI_PanBand},
1466
    {"coastal", GCI_CoastalBand},
1467
    {"blue", GCI_BlueBand},
1468
    {"green", GCI_GreenBand},
1469
    {"green05", GCI_GreenBand},  // no exact match
1470
    {"yellow", GCI_YellowBand},
1471
    {"red", GCI_RedBand},
1472
    {"rededge", GCI_RedEdgeBand},
1473
    {"rededge071", GCI_RedEdgeBand},  // no exact match
1474
    {"rededge075", GCI_RedEdgeBand},  // no exact match
1475
    {"rededge078", GCI_RedEdgeBand},  // no exact match
1476
    {"nir", GCI_NIRBand},
1477
    {"nir08", GCI_NIRBand},   // no exact match
1478
    {"nir09", GCI_NIRBand},   // no exact match
1479
    {"cirrus", GCI_NIRBand},  // no exact match
1480
    {nullptr,
1481
     GCI_SWIRBand},  // so that GDALGetSTACCommonNameFromColorInterp returns null on GCI_SWIRBand
1482
    {"swir16", GCI_SWIRBand},  // no exact match
1483
    {"swir22", GCI_SWIRBand},  // no exact match
1484
    {"lwir", GCI_LWIRBand},
1485
    {"lwir11", GCI_LWIRBand},  // no exact match
1486
    {"lwir12", GCI_LWIRBand},  // no exact match
1487
};
1488
1489
/** Get color interpreetation from STAC eo:common_name
1490
 *
1491
 * Cf https://github.com/stac-extensions/eo?tab=readme-ov-file#common-band-names
1492
 *
1493
 * @since GDAL 3.10
1494
 */
1495
GDALColorInterp GDALGetColorInterpFromSTACCommonName(const char *pszName)
1496
0
{
1497
1498
0
    for (const auto &sAssoc : asSTACCommonNames)
1499
0
    {
1500
0
        if (sAssoc.pszName && EQUAL(pszName, sAssoc.pszName))
1501
0
            return sAssoc.eInterp;
1502
0
    }
1503
0
    return GCI_Undefined;
1504
0
}
1505
1506
/************************************************************************/
1507
/*                GDALGetSTACCommonNameFromColorInterp()                */
1508
/************************************************************************/
1509
1510
/** Get STAC eo:common_name from GDAL color interpretation
1511
 *
1512
 * Cf https://github.com/stac-extensions/eo?tab=readme-ov-file#common-band-names
1513
 *
1514
 * @return nullptr if there is no match
1515
 *
1516
 * @since GDAL 3.10
1517
 */
1518
const char *GDALGetSTACCommonNameFromColorInterp(GDALColorInterp eInterp)
1519
0
{
1520
0
    for (const auto &sAssoc : asSTACCommonNames)
1521
0
    {
1522
0
        if (eInterp == sAssoc.eInterp)
1523
0
            return sAssoc.pszName;
1524
0
    }
1525
0
    return nullptr;
1526
0
}
1527
1528
/************************************************************************/
1529
/*                     GDALGetRandomRasterSample()                      */
1530
/************************************************************************/
1531
1532
/** Undocumented
1533
 * @param hBand undocumented.
1534
 * @param nSamples undocumented.
1535
 * @param pafSampleBuf undocumented.
1536
 * @return undocumented
1537
 */
1538
int CPL_STDCALL GDALGetRandomRasterSample(GDALRasterBandH hBand, int nSamples,
1539
                                          float *pafSampleBuf)
1540
1541
0
{
1542
0
    VALIDATE_POINTER1(hBand, "GDALGetRandomRasterSample", 0);
1543
1544
0
    GDALRasterBand *poBand;
1545
1546
0
    poBand = GDALRasterBand::FromHandle(
1547
0
        GDALGetRasterSampleOverview(hBand, nSamples));
1548
0
    CPLAssert(nullptr != poBand);
1549
1550
    /* -------------------------------------------------------------------- */
1551
    /*      Figure out the ratio of blocks we will read to get an           */
1552
    /*      approximate value.                                              */
1553
    /* -------------------------------------------------------------------- */
1554
0
    int bGotNoDataValue = FALSE;
1555
1556
0
    double dfNoDataValue = poBand->GetNoDataValue(&bGotNoDataValue);
1557
1558
0
    int nBlockXSize = 0;
1559
0
    int nBlockYSize = 0;
1560
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
1561
1562
0
    const int nBlocksPerRow = DIV_ROUND_UP(poBand->GetXSize(), nBlockXSize);
1563
0
    const int nBlocksPerColumn = DIV_ROUND_UP(poBand->GetYSize(), nBlockYSize);
1564
1565
0
    const GIntBig nBlockPixels =
1566
0
        static_cast<GIntBig>(nBlockXSize) * nBlockYSize;
1567
0
    const GIntBig nBlockCount =
1568
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1569
1570
0
    if (nBlocksPerRow == 0 || nBlocksPerColumn == 0 || nBlockPixels == 0 ||
1571
0
        nBlockCount == 0)
1572
0
    {
1573
0
        CPLError(CE_Failure, CPLE_AppDefined,
1574
0
                 "GDALGetRandomRasterSample(): returning because band"
1575
0
                 " appears degenerate.");
1576
1577
0
        return FALSE;
1578
0
    }
1579
1580
0
    int nSampleRate = static_cast<int>(
1581
0
        std::max(1.0, sqrt(static_cast<double>(nBlockCount)) - 2.0));
1582
1583
0
    if (nSampleRate == nBlocksPerRow && nSampleRate > 1)
1584
0
        nSampleRate--;
1585
1586
0
    while (nSampleRate > 1 &&
1587
0
           ((nBlockCount - 1) / nSampleRate + 1) * nBlockPixels < nSamples)
1588
0
        nSampleRate--;
1589
1590
0
    int nBlockSampleRate = 1;
1591
1592
0
    if ((nSamples / ((nBlockCount - 1) / nSampleRate + 1)) != 0)
1593
0
        nBlockSampleRate = static_cast<int>(std::max<GIntBig>(
1594
0
            1,
1595
0
            nBlockPixels / (nSamples / ((nBlockCount - 1) / nSampleRate + 1))));
1596
1597
0
    int nActualSamples = 0;
1598
1599
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nBlockCount;
1600
0
         iSampleBlock += nSampleRate)
1601
0
    {
1602
1603
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
1604
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
1605
1606
0
        GDALRasterBlock *const poBlock =
1607
0
            poBand->GetLockedBlockRef(iXBlock, iYBlock);
1608
0
        if (poBlock == nullptr)
1609
0
            continue;
1610
0
        void *pDataRef = poBlock->GetDataRef();
1611
1612
0
        int iXValid = nBlockXSize;
1613
0
        if ((iXBlock + 1) * nBlockXSize > poBand->GetXSize())
1614
0
            iXValid = poBand->GetXSize() - iXBlock * nBlockXSize;
1615
1616
0
        int iYValid = nBlockYSize;
1617
0
        if ((iYBlock + 1) * nBlockYSize > poBand->GetYSize())
1618
0
            iYValid = poBand->GetYSize() - iYBlock * nBlockYSize;
1619
1620
0
        int iRemainder = 0;
1621
1622
0
        for (int iY = 0; iY < iYValid; iY++)
1623
0
        {
1624
0
            int iX = iRemainder;  // Used after for.
1625
0
            for (; iX < iXValid; iX += nBlockSampleRate)
1626
0
            {
1627
0
                double dfValue = 0.0;
1628
0
                const int iOffset = iX + iY * nBlockXSize;
1629
1630
0
                switch (poBlock->GetDataType())
1631
0
                {
1632
0
                    case GDT_UInt8:
1633
0
                        dfValue =
1634
0
                            reinterpret_cast<const GByte *>(pDataRef)[iOffset];
1635
0
                        break;
1636
0
                    case GDT_Int8:
1637
0
                        dfValue =
1638
0
                            reinterpret_cast<const GInt8 *>(pDataRef)[iOffset];
1639
0
                        break;
1640
0
                    case GDT_UInt16:
1641
0
                        dfValue = reinterpret_cast<const GUInt16 *>(
1642
0
                            pDataRef)[iOffset];
1643
0
                        break;
1644
0
                    case GDT_Int16:
1645
0
                        dfValue =
1646
0
                            reinterpret_cast<const GInt16 *>(pDataRef)[iOffset];
1647
0
                        break;
1648
0
                    case GDT_UInt32:
1649
0
                        dfValue = reinterpret_cast<const GUInt32 *>(
1650
0
                            pDataRef)[iOffset];
1651
0
                        break;
1652
0
                    case GDT_Int32:
1653
0
                        dfValue =
1654
0
                            reinterpret_cast<const GInt32 *>(pDataRef)[iOffset];
1655
0
                        break;
1656
0
                    case GDT_UInt64:
1657
0
                        dfValue = static_cast<double>(
1658
0
                            reinterpret_cast<const std::uint64_t *>(
1659
0
                                pDataRef)[iOffset]);
1660
0
                        break;
1661
0
                    case GDT_Int64:
1662
0
                        dfValue = static_cast<double>(
1663
0
                            reinterpret_cast<const std::int64_t *>(
1664
0
                                pDataRef)[iOffset]);
1665
0
                        break;
1666
0
                    case GDT_Float16:
1667
0
                        dfValue = reinterpret_cast<const GFloat16 *>(
1668
0
                            pDataRef)[iOffset];
1669
0
                        break;
1670
0
                    case GDT_Float32:
1671
0
                        dfValue =
1672
0
                            reinterpret_cast<const float *>(pDataRef)[iOffset];
1673
0
                        break;
1674
0
                    case GDT_Float64:
1675
0
                        dfValue =
1676
0
                            reinterpret_cast<const double *>(pDataRef)[iOffset];
1677
0
                        break;
1678
0
                    case GDT_CInt16:
1679
0
                    {
1680
                        // TODO(schwehr): Clean up casts.
1681
0
                        const double dfReal = reinterpret_cast<const GInt16 *>(
1682
0
                            pDataRef)[iOffset * 2];
1683
0
                        const double dfImag = reinterpret_cast<const GInt16 *>(
1684
0
                            pDataRef)[iOffset * 2 + 1];
1685
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
1686
0
                        break;
1687
0
                    }
1688
0
                    case GDT_CInt32:
1689
0
                    {
1690
0
                        const double dfReal = reinterpret_cast<const GInt32 *>(
1691
0
                            pDataRef)[iOffset * 2];
1692
0
                        const double dfImag = reinterpret_cast<const GInt32 *>(
1693
0
                            pDataRef)[iOffset * 2 + 1];
1694
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
1695
0
                        break;
1696
0
                    }
1697
0
                    case GDT_CFloat16:
1698
0
                    {
1699
0
                        const double dfReal =
1700
0
                            reinterpret_cast<const GFloat16 *>(
1701
0
                                pDataRef)[iOffset * 2];
1702
0
                        const double dfImag =
1703
0
                            reinterpret_cast<const GFloat16 *>(
1704
0
                                pDataRef)[iOffset * 2 + 1];
1705
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
1706
0
                        break;
1707
0
                    }
1708
0
                    case GDT_CFloat32:
1709
0
                    {
1710
0
                        const double dfReal = reinterpret_cast<const float *>(
1711
0
                            pDataRef)[iOffset * 2];
1712
0
                        const double dfImag = reinterpret_cast<const float *>(
1713
0
                            pDataRef)[iOffset * 2 + 1];
1714
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
1715
0
                        break;
1716
0
                    }
1717
0
                    case GDT_CFloat64:
1718
0
                    {
1719
0
                        const double dfReal = reinterpret_cast<const double *>(
1720
0
                            pDataRef)[iOffset * 2];
1721
0
                        const double dfImag = reinterpret_cast<const double *>(
1722
0
                            pDataRef)[iOffset * 2 + 1];
1723
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
1724
0
                        break;
1725
0
                    }
1726
0
                    case GDT_Unknown:
1727
0
                    case GDT_TypeCount:
1728
0
                        CPLAssert(false);
1729
0
                }
1730
1731
0
                if (bGotNoDataValue && dfValue == dfNoDataValue)
1732
0
                    continue;
1733
1734
0
                if (nActualSamples < nSamples)
1735
0
                    pafSampleBuf[nActualSamples++] =
1736
0
                        static_cast<float>(dfValue);
1737
0
            }
1738
1739
0
            iRemainder = iX - iXValid;
1740
0
        }
1741
1742
0
        poBlock->DropLock();
1743
0
    }
1744
1745
0
    return nActualSamples;
1746
0
}
1747
1748
/************************************************************************/
1749
/*                              gdal::GCP                               */
1750
/************************************************************************/
1751
1752
namespace gdal
1753
{
1754
/** Constructor. */
1755
GCP::GCP(const char *pszId, const char *pszInfo, double dfPixel, double dfLine,
1756
         double dfX, double dfY, double dfZ)
1757
138k
    : gcp{CPLStrdup(pszId ? pszId : ""),
1758
138k
          CPLStrdup(pszInfo ? pszInfo : ""),
1759
138k
          dfPixel,
1760
138k
          dfLine,
1761
138k
          dfX,
1762
138k
          dfY,
1763
138k
          dfZ}
1764
138k
{
1765
138k
    static_assert(sizeof(GCP) == sizeof(GDAL_GCP));
1766
138k
}
1767
1768
/** Destructor. */
1769
GCP::~GCP()
1770
454k
{
1771
454k
    CPLFree(gcp.pszId);
1772
454k
    CPLFree(gcp.pszInfo);
1773
454k
}
1774
1775
/** Constructor from a C GDAL_GCP instance. */
1776
GCP::GCP(const GDAL_GCP &other)
1777
289k
    : gcp{CPLStrdup(other.pszId),
1778
289k
          CPLStrdup(other.pszInfo),
1779
289k
          other.dfGCPPixel,
1780
289k
          other.dfGCPLine,
1781
289k
          other.dfGCPX,
1782
289k
          other.dfGCPY,
1783
289k
          other.dfGCPZ}
1784
289k
{
1785
289k
}
1786
1787
/** Copy constructor. */
1788
175k
GCP::GCP(const GCP &other) : GCP(other.gcp)
1789
175k
{
1790
175k
}
1791
1792
/** Move constructor. */
1793
GCP::GCP(GCP &&other)
1794
25.9k
    : gcp{other.gcp.pszId,     other.gcp.pszInfo, other.gcp.dfGCPPixel,
1795
25.9k
          other.gcp.dfGCPLine, other.gcp.dfGCPX,  other.gcp.dfGCPY,
1796
25.9k
          other.gcp.dfGCPZ}
1797
25.9k
{
1798
25.9k
    other.gcp.pszId = nullptr;
1799
25.9k
    other.gcp.pszInfo = nullptr;
1800
25.9k
}
1801
1802
/** Copy assignment operator. */
1803
GCP &GCP::operator=(const GCP &other)
1804
0
{
1805
0
    if (this != &other)
1806
0
    {
1807
0
        CPLFree(gcp.pszId);
1808
0
        CPLFree(gcp.pszInfo);
1809
0
        gcp = other.gcp;
1810
0
        gcp.pszId = CPLStrdup(other.gcp.pszId);
1811
0
        gcp.pszInfo = CPLStrdup(other.gcp.pszInfo);
1812
0
    }
1813
0
    return *this;
1814
0
}
1815
1816
/** Move assignment operator. */
1817
GCP &GCP::operator=(GCP &&other)
1818
0
{
1819
0
    if (this != &other)
1820
0
    {
1821
0
        CPLFree(gcp.pszId);
1822
0
        CPLFree(gcp.pszInfo);
1823
0
        gcp = other.gcp;
1824
0
        other.gcp.pszId = nullptr;
1825
0
        other.gcp.pszInfo = nullptr;
1826
0
    }
1827
0
    return *this;
1828
0
}
1829
1830
/** Set the 'id' member of the GCP. */
1831
void GCP::SetId(const char *pszId)
1832
25.3k
{
1833
25.3k
    CPLFree(gcp.pszId);
1834
25.3k
    gcp.pszId = CPLStrdup(pszId ? pszId : "");
1835
25.3k
}
1836
1837
/** Set the 'info' member of the GCP. */
1838
void GCP::SetInfo(const char *pszInfo)
1839
25.3k
{
1840
25.3k
    CPLFree(gcp.pszInfo);
1841
25.3k
    gcp.pszInfo = CPLStrdup(pszInfo ? pszInfo : "");
1842
25.3k
}
1843
1844
/** Cast a vector of gdal::GCP as a C array of GDAL_GCP. */
1845
/*static */
1846
const GDAL_GCP *GCP::c_ptr(const std::vector<GCP> &asGCPs)
1847
79.4k
{
1848
79.4k
    return asGCPs.empty() ? nullptr : asGCPs.front().c_ptr();
1849
79.4k
}
1850
1851
/** Creates a vector of GDAL::GCP from a C array of GDAL_GCP. */
1852
/*static*/
1853
std::vector<GCP> GCP::fromC(const GDAL_GCP *pasGCPList, int nGCPCount)
1854
9.32k
{
1855
9.32k
    return std::vector<GCP>(pasGCPList, pasGCPList + nGCPCount);
1856
9.32k
}
1857
1858
} /* namespace gdal */
1859
1860
/************************************************************************/
1861
/*                            GDALInitGCPs()                            */
1862
/************************************************************************/
1863
1864
/** Initialize an array of GCPs.
1865
 *
1866
 * Numeric values are initialized to 0 and strings to the empty string ""
1867
 * allocated with CPLStrdup()
1868
 * An array initialized with GDALInitGCPs() must be de-initialized with
1869
 * GDALDeinitGCPs().
1870
 *
1871
 * @param nCount number of GCPs in psGCP
1872
 * @param psGCP array of GCPs of size nCount.
1873
 */
1874
void CPL_STDCALL GDALInitGCPs(int nCount, GDAL_GCP *psGCP)
1875
1876
4.52k
{
1877
4.52k
    if (nCount > 0)
1878
4.52k
    {
1879
4.52k
        VALIDATE_POINTER0(psGCP, "GDALInitGCPs");
1880
4.52k
    }
1881
1882
945k
    for (int iGCP = 0; iGCP < nCount; iGCP++)
1883
940k
    {
1884
940k
        memset(psGCP, 0, sizeof(GDAL_GCP));
1885
940k
        psGCP->pszId = CPLStrdup("");
1886
940k
        psGCP->pszInfo = CPLStrdup("");
1887
940k
        psGCP++;
1888
940k
    }
1889
4.52k
}
1890
1891
/************************************************************************/
1892
/*                           GDALDeinitGCPs()                           */
1893
/************************************************************************/
1894
1895
/** De-initialize an array of GCPs (initialized with GDALInitGCPs())
1896
 *
1897
 * @param nCount number of GCPs in psGCP
1898
 * @param psGCP array of GCPs of size nCount.
1899
 */
1900
void CPL_STDCALL GDALDeinitGCPs(int nCount, GDAL_GCP *psGCP)
1901
1902
4.34k
{
1903
4.34k
    if (nCount > 0)
1904
2.20k
    {
1905
2.20k
        VALIDATE_POINTER0(psGCP, "GDALDeinitGCPs");
1906
2.20k
    }
1907
1908
945k
    for (int iGCP = 0; iGCP < nCount; iGCP++)
1909
941k
    {
1910
941k
        CPLFree(psGCP->pszId);
1911
941k
        CPLFree(psGCP->pszInfo);
1912
941k
        psGCP++;
1913
941k
    }
1914
4.34k
}
1915
1916
/************************************************************************/
1917
/*                         GDALDuplicateGCPs()                          */
1918
/************************************************************************/
1919
1920
/** Duplicate an array of GCPs
1921
 *
1922
 * The return must be freed with GDALDeinitGCPs() followed by CPLFree()
1923
 *
1924
 * @param nCount number of GCPs in psGCP
1925
 * @param pasGCPList array of GCPs of size nCount.
1926
 */
1927
GDAL_GCP *CPL_STDCALL GDALDuplicateGCPs(int nCount, const GDAL_GCP *pasGCPList)
1928
1929
100
{
1930
100
    GDAL_GCP *pasReturn =
1931
100
        static_cast<GDAL_GCP *>(CPLMalloc(sizeof(GDAL_GCP) * nCount));
1932
100
    GDALInitGCPs(nCount, pasReturn);
1933
1934
20.6k
    for (int iGCP = 0; iGCP < nCount; iGCP++)
1935
20.5k
    {
1936
20.5k
        CPLFree(pasReturn[iGCP].pszId);
1937
20.5k
        pasReturn[iGCP].pszId = CPLStrdup(pasGCPList[iGCP].pszId);
1938
1939
20.5k
        CPLFree(pasReturn[iGCP].pszInfo);
1940
20.5k
        pasReturn[iGCP].pszInfo = CPLStrdup(pasGCPList[iGCP].pszInfo);
1941
1942
20.5k
        pasReturn[iGCP].dfGCPPixel = pasGCPList[iGCP].dfGCPPixel;
1943
20.5k
        pasReturn[iGCP].dfGCPLine = pasGCPList[iGCP].dfGCPLine;
1944
20.5k
        pasReturn[iGCP].dfGCPX = pasGCPList[iGCP].dfGCPX;
1945
20.5k
        pasReturn[iGCP].dfGCPY = pasGCPList[iGCP].dfGCPY;
1946
20.5k
        pasReturn[iGCP].dfGCPZ = pasGCPList[iGCP].dfGCPZ;
1947
20.5k
    }
1948
1949
100
    return pasReturn;
1950
100
}
1951
1952
/************************************************************************/
1953
/*                       GDALFindAssociatedFile()                       */
1954
/************************************************************************/
1955
1956
/**
1957
 * \brief Find file with alternate extension.
1958
 *
1959
 * Finds the file with the indicated extension, substituting it in place
1960
 * of the extension of the base filename.  Generally used to search for
1961
 * associated files like world files .RPB files, etc.  If necessary, the
1962
 * extension will be tried in both upper and lower case.  If a sibling file
1963
 * list is available it will be used instead of doing VSIStatExL() calls to
1964
 * probe the file system.
1965
 *
1966
 * Note that the result is a dynamic CPLString so this method should not
1967
 * be used in a situation where there could be cross heap issues.  It is
1968
 * generally imprudent for application built on GDAL to use this function
1969
 * unless they are sure they will always use the same runtime heap as GDAL.
1970
 *
1971
 * @param pszBaseFilename the filename relative to which to search.
1972
 * @param pszExt the target extension in either upper or lower case.
1973
 * @param papszSiblingFiles the list of files in the same directory as
1974
 * pszBaseFilename or NULL if they are not known.
1975
 * @param nFlags special options controlling search.  None defined yet, just
1976
 * pass 0.
1977
 *
1978
 * @return an empty string if the target is not found, otherwise the target
1979
 * file with similar path style as the pszBaseFilename.
1980
 */
1981
1982
/**/
1983
/**/
1984
1985
CPLString GDALFindAssociatedFile(const char *pszBaseFilename,
1986
                                 const char *pszExt,
1987
                                 CSLConstList papszSiblingFiles,
1988
                                 CPL_UNUSED int nFlags)
1989
1990
761k
{
1991
761k
    CPLString osTarget = CPLResetExtensionSafe(pszBaseFilename, pszExt);
1992
1993
761k
    if (papszSiblingFiles == nullptr ||
1994
        // cppcheck-suppress knownConditionTrueFalse
1995
759k
        !GDALCanReliablyUseSiblingFileList(osTarget.c_str()))
1996
1.19k
    {
1997
1.19k
        VSIStatBufL sStatBuf;
1998
1999
1.19k
        if (VSIStatExL(osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
2000
1.19k
        {
2001
1.19k
            CPLString osAltExt = pszExt;
2002
2003
1.19k
            if (islower(static_cast<unsigned char>(pszExt[0])))
2004
0
                osAltExt = osAltExt.toupper();
2005
1.19k
            else
2006
1.19k
                osAltExt = osAltExt.tolower();
2007
2008
1.19k
            osTarget = CPLResetExtensionSafe(pszBaseFilename, osAltExt);
2009
2010
1.19k
            if (VSIStatExL(osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
2011
1.19k
                return "";
2012
1.19k
        }
2013
1.19k
    }
2014
759k
    else
2015
759k
    {
2016
759k
        const int iSibling =
2017
759k
            CSLFindString(papszSiblingFiles, CPLGetFilename(osTarget));
2018
759k
        if (iSibling < 0)
2019
758k
            return "";
2020
2021
1.04k
        osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
2022
1.04k
        osTarget += papszSiblingFiles[iSibling];
2023
1.04k
    }
2024
2025
1.04k
    return osTarget;
2026
761k
}
2027
2028
/************************************************************************/
2029
/*                         GDALLoadOziMapFile()                         */
2030
/************************************************************************/
2031
2032
/** Helper function for translator implementer wanting support for OZI .map
2033
 *
2034
 * @param pszFilename filename of .tab file
2035
 * @param padfGeoTransform output geotransform. Must hold 6 doubles.
2036
 * @param ppszWKT output pointer to a string that will be allocated with
2037
 * CPLMalloc().
2038
 * @param pnGCPCount output pointer to GCP count.
2039
 * @param ppasGCPs outputer pointer to an array of GCPs.
2040
 * @return TRUE in case of success, FALSE otherwise.
2041
 */
2042
int CPL_STDCALL GDALLoadOziMapFile(const char *pszFilename,
2043
                                   double *padfGeoTransform, char **ppszWKT,
2044
                                   int *pnGCPCount, GDAL_GCP **ppasGCPs)
2045
2046
265
{
2047
265
    VALIDATE_POINTER1(pszFilename, "GDALLoadOziMapFile", FALSE);
2048
265
    VALIDATE_POINTER1(padfGeoTransform, "GDALLoadOziMapFile", FALSE);
2049
265
    VALIDATE_POINTER1(pnGCPCount, "GDALLoadOziMapFile", FALSE);
2050
265
    VALIDATE_POINTER1(ppasGCPs, "GDALLoadOziMapFile", FALSE);
2051
2052
265
    char **papszLines = CSLLoad2(pszFilename, 1000, 200, nullptr);
2053
2054
265
    if (!papszLines)
2055
3
        return FALSE;
2056
2057
262
    int nLines = CSLCount(papszLines);
2058
2059
    // Check the OziExplorer Map file signature
2060
262
    if (nLines < 5 ||
2061
88
        !STARTS_WITH_CI(papszLines[0], "OziExplorer Map Data File Version "))
2062
262
    {
2063
262
        CPLError(CE_Failure, CPLE_AppDefined,
2064
262
                 "GDALLoadOziMapFile(): file \"%s\" is not in OziExplorer Map "
2065
262
                 "format.",
2066
262
                 pszFilename);
2067
262
        CSLDestroy(papszLines);
2068
262
        return FALSE;
2069
262
    }
2070
2071
0
    OGRSpatialReference oSRS;
2072
0
    OGRErr eErr = OGRERR_NONE;
2073
2074
    /* The Map Scale Factor has been introduced recently on the 6th line */
2075
    /* and is a trick that is used to just change that line without changing */
2076
    /* the rest of the MAP file but providing an imagery that is smaller or
2077
     * larger */
2078
    /* so we have to correct the pixel/line values read in the .MAP file so they
2079
     */
2080
    /* match the actual imagery dimension. Well, this is a bad summary of what
2081
     */
2082
    /* is explained at
2083
     * http://tech.groups.yahoo.com/group/OziUsers-L/message/12484 */
2084
0
    double dfMSF = 1;
2085
2086
0
    for (int iLine = 5; iLine < nLines; iLine++)
2087
0
    {
2088
0
        if (STARTS_WITH_CI(papszLines[iLine], "MSF,"))
2089
0
        {
2090
0
            dfMSF = CPLAtof(papszLines[iLine] + 4);
2091
0
            if (dfMSF <= 0.01) /* Suspicious values */
2092
0
            {
2093
0
                CPLDebug("OZI", "Suspicious MSF value : %s", papszLines[iLine]);
2094
0
                dfMSF = 1;
2095
0
            }
2096
0
        }
2097
0
    }
2098
2099
0
    eErr = oSRS.importFromOzi(papszLines);
2100
0
    if (eErr == OGRERR_NONE)
2101
0
    {
2102
0
        if (ppszWKT != nullptr)
2103
0
            oSRS.exportToWkt(ppszWKT);
2104
0
    }
2105
2106
0
    int nCoordinateCount = 0;
2107
    // TODO(schwehr): Initialize asGCPs.
2108
0
    GDAL_GCP asGCPs[30];
2109
2110
    // Iterate all lines in the MAP-file
2111
0
    for (int iLine = 5; iLine < nLines; iLine++)
2112
0
    {
2113
0
        char **papszTok = CSLTokenizeString2(
2114
0
            papszLines[iLine], ",",
2115
0
            CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
2116
2117
0
        if (CSLCount(papszTok) < 12)
2118
0
        {
2119
0
            CSLDestroy(papszTok);
2120
0
            continue;
2121
0
        }
2122
2123
0
        if (CSLCount(papszTok) >= 17 && STARTS_WITH_CI(papszTok[0], "Point") &&
2124
0
            !EQUAL(papszTok[2], "") && !EQUAL(papszTok[3], "") &&
2125
0
            nCoordinateCount < static_cast<int>(CPL_ARRAYSIZE(asGCPs)))
2126
0
        {
2127
0
            bool bReadOk = false;
2128
0
            double dfLon = 0.0;
2129
0
            double dfLat = 0.0;
2130
2131
0
            if (!EQUAL(papszTok[6], "") && !EQUAL(papszTok[7], "") &&
2132
0
                !EQUAL(papszTok[9], "") && !EQUAL(papszTok[10], ""))
2133
0
            {
2134
                // Set geographical coordinates of the pixels
2135
0
                dfLon = CPLAtofM(papszTok[9]) + CPLAtofM(papszTok[10]) / 60.0;
2136
0
                dfLat = CPLAtofM(papszTok[6]) + CPLAtofM(papszTok[7]) / 60.0;
2137
0
                if (EQUAL(papszTok[11], "W"))
2138
0
                    dfLon = -dfLon;
2139
0
                if (EQUAL(papszTok[8], "S"))
2140
0
                    dfLat = -dfLat;
2141
2142
                // Transform from the geographical coordinates into projected
2143
                // coordinates.
2144
0
                if (eErr == OGRERR_NONE)
2145
0
                {
2146
0
                    OGRSpatialReference *poLongLat = oSRS.CloneGeogCS();
2147
2148
0
                    if (poLongLat)
2149
0
                    {
2150
0
                        oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2151
0
                        poLongLat->SetAxisMappingStrategy(
2152
0
                            OAMS_TRADITIONAL_GIS_ORDER);
2153
2154
0
                        OGRCoordinateTransformation *poTransform =
2155
0
                            OGRCreateCoordinateTransformation(poLongLat, &oSRS);
2156
0
                        if (poTransform)
2157
0
                        {
2158
0
                            bReadOk = CPL_TO_BOOL(
2159
0
                                poTransform->Transform(1, &dfLon, &dfLat));
2160
0
                            delete poTransform;
2161
0
                        }
2162
0
                        delete poLongLat;
2163
0
                    }
2164
0
                }
2165
0
            }
2166
0
            else if (!EQUAL(papszTok[14], "") && !EQUAL(papszTok[15], ""))
2167
0
            {
2168
                // Set cartesian coordinates of the pixels.
2169
0
                dfLon = CPLAtofM(papszTok[14]);
2170
0
                dfLat = CPLAtofM(papszTok[15]);
2171
0
                bReadOk = true;
2172
2173
                // if ( EQUAL(papszTok[16], "S") )
2174
                //     dfLat = -dfLat;
2175
0
            }
2176
2177
0
            if (bReadOk)
2178
0
            {
2179
0
                GDALInitGCPs(1, asGCPs + nCoordinateCount);
2180
2181
                // Set pixel/line part
2182
0
                asGCPs[nCoordinateCount].dfGCPPixel =
2183
0
                    CPLAtofM(papszTok[2]) / dfMSF;
2184
0
                asGCPs[nCoordinateCount].dfGCPLine =
2185
0
                    CPLAtofM(papszTok[3]) / dfMSF;
2186
2187
0
                asGCPs[nCoordinateCount].dfGCPX = dfLon;
2188
0
                asGCPs[nCoordinateCount].dfGCPY = dfLat;
2189
2190
0
                nCoordinateCount++;
2191
0
            }
2192
0
        }
2193
2194
0
        CSLDestroy(papszTok);
2195
0
    }
2196
2197
0
    CSLDestroy(papszLines);
2198
2199
0
    if (nCoordinateCount == 0)
2200
0
    {
2201
0
        CPLDebug("GDAL", "GDALLoadOziMapFile(\"%s\") did read no GCPs.",
2202
0
                 pszFilename);
2203
0
        return FALSE;
2204
0
    }
2205
2206
    /* -------------------------------------------------------------------- */
2207
    /*      Try to convert the GCPs into a geotransform definition, if      */
2208
    /*      possible.  Otherwise we will need to use them as GCPs.          */
2209
    /* -------------------------------------------------------------------- */
2210
0
    if (!GDALGCPsToGeoTransform(
2211
0
            nCoordinateCount, asGCPs, padfGeoTransform,
2212
0
            CPLTestBool(CPLGetConfigOption("OZI_APPROX_GEOTRANSFORM", "NO"))))
2213
0
    {
2214
0
        if (pnGCPCount && ppasGCPs)
2215
0
        {
2216
0
            CPLDebug(
2217
0
                "GDAL",
2218
0
                "GDALLoadOziMapFile(%s) found file, was not able to derive a\n"
2219
0
                "first order geotransform.  Using points as GCPs.",
2220
0
                pszFilename);
2221
2222
0
            *ppasGCPs = static_cast<GDAL_GCP *>(
2223
0
                CPLCalloc(sizeof(GDAL_GCP), nCoordinateCount));
2224
0
            memcpy(*ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount);
2225
0
            *pnGCPCount = nCoordinateCount;
2226
0
        }
2227
0
    }
2228
0
    else
2229
0
    {
2230
0
        GDALDeinitGCPs(nCoordinateCount, asGCPs);
2231
0
    }
2232
2233
0
    return TRUE;
2234
0
}
2235
2236
/************************************************************************/
2237
/*                         GDALReadOziMapFile()                         */
2238
/************************************************************************/
2239
2240
/** Helper function for translator implementer wanting support for OZI .map
2241
 *
2242
 * @param pszBaseFilename filename whose basename will help building the .map
2243
 * filename.
2244
 * @param padfGeoTransform output geotransform. Must hold 6 doubles.
2245
 * @param ppszWKT output pointer to a string that will be allocated with
2246
 * CPLMalloc().
2247
 * @param pnGCPCount output pointer to GCP count.
2248
 * @param ppasGCPs outputer pointer to an array of GCPs.
2249
 * @return TRUE in case of success, FALSE otherwise.
2250
 */
2251
int CPL_STDCALL GDALReadOziMapFile(const char *pszBaseFilename,
2252
                                   double *padfGeoTransform, char **ppszWKT,
2253
                                   int *pnGCPCount, GDAL_GCP **ppasGCPs)
2254
2255
0
{
2256
    /* -------------------------------------------------------------------- */
2257
    /*      Try lower case, then upper case.                                */
2258
    /* -------------------------------------------------------------------- */
2259
0
    std::string osOzi = CPLResetExtensionSafe(pszBaseFilename, "map");
2260
2261
0
    VSILFILE *fpOzi = VSIFOpenL(osOzi.c_str(), "rt");
2262
2263
0
    if (fpOzi == nullptr && VSIIsCaseSensitiveFS(osOzi.c_str()))
2264
0
    {
2265
0
        osOzi = CPLResetExtensionSafe(pszBaseFilename, "MAP");
2266
0
        fpOzi = VSIFOpenL(osOzi.c_str(), "rt");
2267
0
    }
2268
2269
0
    if (fpOzi == nullptr)
2270
0
        return FALSE;
2271
2272
0
    CPL_IGNORE_RET_VAL(VSIFCloseL(fpOzi));
2273
2274
    /* -------------------------------------------------------------------- */
2275
    /*      We found the file, now load and parse it.                       */
2276
    /* -------------------------------------------------------------------- */
2277
0
    return GDALLoadOziMapFile(osOzi.c_str(), padfGeoTransform, ppszWKT,
2278
0
                              pnGCPCount, ppasGCPs);
2279
0
}
2280
2281
/************************************************************************/
2282
/*                         GDALLoadTabFile()                            */
2283
/*                                                                      */
2284
/************************************************************************/
2285
2286
/** Helper function for translator implementer wanting support for MapInfo
2287
 * .tab files.
2288
 *
2289
 * @param pszFilename filename of .tab
2290
 * @param padfGeoTransform output geotransform. Must hold 6 doubles.
2291
 * @param ppszWKT output pointer to a string that will be allocated with
2292
 * CPLMalloc().
2293
 * @param pnGCPCount output pointer to GCP count.
2294
 * @param ppasGCPs outputer pointer to an array of GCPs.
2295
 * @return TRUE in case of success, FALSE otherwise.
2296
 */
2297
int CPL_STDCALL GDALLoadTabFile(const char *pszFilename,
2298
                                double *padfGeoTransform, char **ppszWKT,
2299
                                int *pnGCPCount, GDAL_GCP **ppasGCPs)
2300
2301
123
{
2302
123
    char **papszLines = CSLLoad2(pszFilename, 1000, 200, nullptr);
2303
2304
123
    if (!papszLines)
2305
2
        return FALSE;
2306
2307
121
    char **papszTok = nullptr;
2308
121
    bool bTypeRasterFound = false;
2309
121
    bool bInsideTableDef = false;
2310
121
    int nCoordinateCount = 0;
2311
121
    GDAL_GCP asGCPs[256];  // TODO(schwehr): Initialize.
2312
121
    const int numLines = CSLCount(papszLines);
2313
2314
    // Iterate all lines in the TAB-file
2315
13.4k
    for (int iLine = 0; iLine < numLines; iLine++)
2316
13.3k
    {
2317
13.3k
        CSLDestroy(papszTok);
2318
13.3k
        papszTok =
2319
13.3k
            CSLTokenizeStringComplex(papszLines[iLine], " \t(),;", TRUE, FALSE);
2320
2321
13.3k
        if (CSLCount(papszTok) < 2)
2322
10.3k
            continue;
2323
2324
        // Did we find table definition
2325
2.98k
        if (EQUAL(papszTok[0], "Definition") && EQUAL(papszTok[1], "Table"))
2326
0
        {
2327
0
            bInsideTableDef = TRUE;
2328
0
        }
2329
2.98k
        else if (bInsideTableDef && (EQUAL(papszTok[0], "Type")))
2330
0
        {
2331
            // Only RASTER-type will be handled
2332
0
            if (EQUAL(papszTok[1], "RASTER"))
2333
0
            {
2334
0
                bTypeRasterFound = true;
2335
0
            }
2336
0
            else
2337
0
            {
2338
0
                CSLDestroy(papszTok);
2339
0
                CSLDestroy(papszLines);
2340
0
                return FALSE;
2341
0
            }
2342
0
        }
2343
2.98k
        else if (bTypeRasterFound && bInsideTableDef &&
2344
0
                 CSLCount(papszTok) > 4 && EQUAL(papszTok[4], "Label") &&
2345
0
                 nCoordinateCount < static_cast<int>(CPL_ARRAYSIZE(asGCPs)))
2346
0
        {
2347
0
            GDALInitGCPs(1, asGCPs + nCoordinateCount);
2348
2349
0
            asGCPs[nCoordinateCount].dfGCPPixel = CPLAtofM(papszTok[2]);
2350
0
            asGCPs[nCoordinateCount].dfGCPLine = CPLAtofM(papszTok[3]);
2351
0
            asGCPs[nCoordinateCount].dfGCPX = CPLAtofM(papszTok[0]);
2352
0
            asGCPs[nCoordinateCount].dfGCPY = CPLAtofM(papszTok[1]);
2353
0
            if (papszTok[5] != nullptr)
2354
0
            {
2355
0
                CPLFree(asGCPs[nCoordinateCount].pszId);
2356
0
                asGCPs[nCoordinateCount].pszId = CPLStrdup(papszTok[5]);
2357
0
            }
2358
2359
0
            nCoordinateCount++;
2360
0
        }
2361
2.98k
        else if (bTypeRasterFound && bInsideTableDef &&
2362
0
                 EQUAL(papszTok[0], "CoordSys") && ppszWKT != nullptr)
2363
0
        {
2364
0
            OGRSpatialReference oSRS;
2365
2366
0
            if (oSRS.importFromMICoordSys(papszLines[iLine]) == OGRERR_NONE)
2367
0
                oSRS.exportToWkt(ppszWKT);
2368
0
        }
2369
2.98k
        else if (EQUAL(papszTok[0], "Units") && CSLCount(papszTok) > 1 &&
2370
127
                 EQUAL(papszTok[1], "degree"))
2371
0
        {
2372
            /*
2373
            ** If we have units of "degree", but a projected coordinate
2374
            ** system we need to convert it to geographic.  See to01_02.TAB.
2375
            */
2376
0
            if (ppszWKT != nullptr && *ppszWKT != nullptr &&
2377
0
                STARTS_WITH_CI(*ppszWKT, "PROJCS"))
2378
0
            {
2379
0
                OGRSpatialReference oSRS;
2380
0
                oSRS.importFromWkt(*ppszWKT);
2381
2382
0
                OGRSpatialReference oSRSGeogCS;
2383
0
                oSRSGeogCS.CopyGeogCSFrom(&oSRS);
2384
0
                CPLFree(*ppszWKT);
2385
2386
0
                oSRSGeogCS.exportToWkt(ppszWKT);
2387
0
            }
2388
0
        }
2389
2.98k
    }
2390
2391
121
    CSLDestroy(papszTok);
2392
121
    CSLDestroy(papszLines);
2393
2394
121
    if (nCoordinateCount == 0)
2395
121
    {
2396
121
        CPLDebug("GDAL", "GDALLoadTabFile(%s) did not get any GCPs.",
2397
121
                 pszFilename);
2398
121
        return FALSE;
2399
121
    }
2400
2401
    /* -------------------------------------------------------------------- */
2402
    /*      Try to convert the GCPs into a geotransform definition, if      */
2403
    /*      possible.  Otherwise we will need to use them as GCPs.          */
2404
    /* -------------------------------------------------------------------- */
2405
0
    if (!GDALGCPsToGeoTransform(
2406
0
            nCoordinateCount, asGCPs, padfGeoTransform,
2407
0
            CPLTestBool(CPLGetConfigOption("TAB_APPROX_GEOTRANSFORM", "NO"))))
2408
0
    {
2409
0
        if (pnGCPCount && ppasGCPs)
2410
0
        {
2411
0
            CPLDebug("GDAL",
2412
0
                     "GDALLoadTabFile(%s) found file, was not able to derive a "
2413
0
                     "first order geotransform.  Using points as GCPs.",
2414
0
                     pszFilename);
2415
2416
0
            *ppasGCPs = static_cast<GDAL_GCP *>(
2417
0
                CPLCalloc(sizeof(GDAL_GCP), nCoordinateCount));
2418
0
            memcpy(*ppasGCPs, asGCPs, sizeof(GDAL_GCP) * nCoordinateCount);
2419
0
            *pnGCPCount = nCoordinateCount;
2420
0
        }
2421
0
    }
2422
0
    else
2423
0
    {
2424
0
        GDALDeinitGCPs(nCoordinateCount, asGCPs);
2425
0
    }
2426
2427
0
    return TRUE;
2428
121
}
2429
2430
/************************************************************************/
2431
/*                          GDALReadTabFile()                           */
2432
/************************************************************************/
2433
2434
/** Helper function for translator implementer wanting support for MapInfo
2435
 * .tab files.
2436
 *
2437
 * @param pszBaseFilename filename whose basename will help building the .tab
2438
 * filename.
2439
 * @param padfGeoTransform output geotransform. Must hold 6 doubles.
2440
 * @param ppszWKT output pointer to a string that will be allocated with
2441
 * CPLMalloc().
2442
 * @param pnGCPCount output pointer to GCP count.
2443
 * @param ppasGCPs outputer pointer to an array of GCPs.
2444
 * @return TRUE in case of success, FALSE otherwise.
2445
 */
2446
int CPL_STDCALL GDALReadTabFile(const char *pszBaseFilename,
2447
                                double *padfGeoTransform, char **ppszWKT,
2448
                                int *pnGCPCount, GDAL_GCP **ppasGCPs)
2449
2450
0
{
2451
0
    return GDALReadTabFile2(pszBaseFilename, padfGeoTransform, ppszWKT,
2452
0
                            pnGCPCount, ppasGCPs, nullptr, nullptr);
2453
0
}
2454
2455
int GDALReadTabFile2(const char *pszBaseFilename, double *padfGeoTransform,
2456
                     char **ppszWKT, int *pnGCPCount, GDAL_GCP **ppasGCPs,
2457
                     CSLConstList papszSiblingFiles, char **ppszTabFileNameOut)
2458
108k
{
2459
108k
    if (ppszTabFileNameOut)
2460
108k
        *ppszTabFileNameOut = nullptr;
2461
2462
108k
    if (!GDALCanFileAcceptSidecarFile(pszBaseFilename))
2463
0
        return FALSE;
2464
2465
108k
    std::string osTAB = CPLResetExtensionSafe(pszBaseFilename, "tab");
2466
2467
108k
    if (papszSiblingFiles &&
2468
        // cppcheck-suppress knownConditionTrueFalse
2469
108k
        GDALCanReliablyUseSiblingFileList(osTAB.c_str()))
2470
108k
    {
2471
108k
        int iSibling =
2472
108k
            CSLFindString(papszSiblingFiles, CPLGetFilename(osTAB.c_str()));
2473
108k
        if (iSibling >= 0)
2474
123
        {
2475
123
            CPLString osTabFilename = pszBaseFilename;
2476
123
            osTabFilename.resize(strlen(pszBaseFilename) -
2477
123
                                 strlen(CPLGetFilename(pszBaseFilename)));
2478
123
            osTabFilename += papszSiblingFiles[iSibling];
2479
123
            if (GDALLoadTabFile(osTabFilename, padfGeoTransform, ppszWKT,
2480
123
                                pnGCPCount, ppasGCPs))
2481
0
            {
2482
0
                if (ppszTabFileNameOut)
2483
0
                    *ppszTabFileNameOut = CPLStrdup(osTabFilename);
2484
0
                return TRUE;
2485
0
            }
2486
123
        }
2487
108k
        return FALSE;
2488
108k
    }
2489
2490
    /* -------------------------------------------------------------------- */
2491
    /*      Try lower case, then upper case.                                */
2492
    /* -------------------------------------------------------------------- */
2493
2494
171
    VSILFILE *fpTAB = VSIFOpenL(osTAB.c_str(), "rt");
2495
2496
171
    if (fpTAB == nullptr && VSIIsCaseSensitiveFS(osTAB.c_str()))
2497
171
    {
2498
171
        osTAB = CPLResetExtensionSafe(pszBaseFilename, "TAB");
2499
171
        fpTAB = VSIFOpenL(osTAB.c_str(), "rt");
2500
171
    }
2501
2502
171
    if (fpTAB == nullptr)
2503
171
        return FALSE;
2504
2505
0
    CPL_IGNORE_RET_VAL(VSIFCloseL(fpTAB));
2506
2507
    /* -------------------------------------------------------------------- */
2508
    /*      We found the file, now load and parse it.                       */
2509
    /* -------------------------------------------------------------------- */
2510
0
    if (GDALLoadTabFile(osTAB.c_str(), padfGeoTransform, ppszWKT, pnGCPCount,
2511
0
                        ppasGCPs))
2512
0
    {
2513
0
        if (ppszTabFileNameOut)
2514
0
            *ppszTabFileNameOut = CPLStrdup(osTAB.c_str());
2515
0
        return TRUE;
2516
0
    }
2517
0
    return FALSE;
2518
0
}
2519
2520
/************************************************************************/
2521
/*                         GDALLoadWorldFile()                          */
2522
/************************************************************************/
2523
2524
/**
2525
 * \brief Read ESRI world file.
2526
 *
2527
 * This function reads an ESRI style world file, and formats a geotransform
2528
 * from its contents.
2529
 *
2530
 * The world file contains an affine transformation with the parameters
2531
 * in a different order than in a geotransform array.
2532
 *
2533
 * <ul>
2534
 * <li> geotransform[1] : width of pixel</li>
2535
 * <li> geotransform[4] : rotational coefficient, zero for north up images.</li>
2536
 * <li> geotransform[2] : rotational coefficient, zero for north up images.</li>
2537
 * <li> geotransform[5] : height of pixel (but negative)</li>
2538
 * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x
2539
 * offset to center of top left pixel.</li>
2540
 * <li> geotransform[3] + 0.5 *
2541
 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left
2542
 * pixel.</li>
2543
 * </ul>
2544
 *
2545
 * @param pszFilename the world file name.
2546
 * @param padfGeoTransform the six double array into which the
2547
 * geotransformation should be placed.
2548
 *
2549
 * @return TRUE on success or FALSE on failure.
2550
 */
2551
2552
int CPL_STDCALL GDALLoadWorldFile(const char *pszFilename,
2553
                                  double *padfGeoTransform)
2554
2555
792
{
2556
792
    VALIDATE_POINTER1(pszFilename, "GDALLoadWorldFile", FALSE);
2557
792
    VALIDATE_POINTER1(padfGeoTransform, "GDALLoadWorldFile", FALSE);
2558
2559
792
    char **papszLines = CSLLoad2(pszFilename, 100, 100, nullptr);
2560
2561
792
    if (!papszLines)
2562
69
        return FALSE;
2563
2564
723
    double world[6] = {0.0};
2565
    // reads the first 6 non-empty lines
2566
723
    int nLines = 0;
2567
723
    const int nLinesCount = CSLCount(papszLines);
2568
723
    for (int i = 0;
2569
6.70k
         i < nLinesCount && nLines < static_cast<int>(CPL_ARRAYSIZE(world));
2570
5.98k
         ++i)
2571
5.98k
    {
2572
5.98k
        CPLString line(papszLines[i]);
2573
5.98k
        if (line.Trim().empty())
2574
2.50k
            continue;
2575
2576
3.48k
        world[nLines] = CPLAtofM(line);
2577
3.48k
        ++nLines;
2578
3.48k
    }
2579
2580
723
    if (nLines == 6 && (world[0] != 0.0 || world[2] != 0.0) &&
2581
141
        (world[3] != 0.0 || world[1] != 0.0))
2582
114
    {
2583
114
        padfGeoTransform[0] = world[4];
2584
114
        padfGeoTransform[1] = world[0];
2585
114
        padfGeoTransform[2] = world[2];
2586
114
        padfGeoTransform[3] = world[5];
2587
114
        padfGeoTransform[4] = world[1];
2588
114
        padfGeoTransform[5] = world[3];
2589
2590
        // correct for center of pixel vs. top left of pixel
2591
114
        padfGeoTransform[0] -= 0.5 * padfGeoTransform[1];
2592
114
        padfGeoTransform[0] -= 0.5 * padfGeoTransform[2];
2593
114
        padfGeoTransform[3] -= 0.5 * padfGeoTransform[4];
2594
114
        padfGeoTransform[3] -= 0.5 * padfGeoTransform[5];
2595
2596
114
        CSLDestroy(papszLines);
2597
2598
114
        return TRUE;
2599
114
    }
2600
609
    else
2601
609
    {
2602
609
        CPLDebug("GDAL",
2603
609
                 "GDALLoadWorldFile(%s) found file, but it was corrupt.",
2604
609
                 pszFilename);
2605
609
        CSLDestroy(papszLines);
2606
609
        return FALSE;
2607
609
    }
2608
723
}
2609
2610
/************************************************************************/
2611
/*                         GDALReadWorldFile()                          */
2612
/************************************************************************/
2613
2614
/**
2615
 * \brief Read ESRI world file.
2616
 *
2617
 * This function reads an ESRI style world file, and formats a geotransform
2618
 * from its contents.  It does the same as GDALLoadWorldFile() function, but
2619
 * it will form the filename for the worldfile from the filename of the raster
2620
 * file referred and the suggested extension.  If no extension is provided,
2621
 * the code will internally try the unix style and windows style world file
2622
 * extensions (eg. for .tif these would be .tfw and .tifw).
2623
 *
2624
 * The world file contains an affine transformation with the parameters
2625
 * in a different order than in a geotransform array.
2626
 *
2627
 * <ul>
2628
 * <li> geotransform[1] : width of pixel</li>
2629
 * <li> geotransform[4] : rotational coefficient, zero for north up images.</li>
2630
 * <li> geotransform[2] : rotational coefficient, zero for north up images.</li>
2631
 * <li> geotransform[5] : height of pixel (but negative)</li>
2632
 * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x
2633
 * offset to center of top left pixel.</li>
2634
 * <li> geotransform[3] + 0.5 *
2635
 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left
2636
 * pixel.</li>
2637
 * </ul>
2638
 *
2639
 * @param pszBaseFilename the target raster file.
2640
 * @param pszExtension the extension to use (i.e. "wld") or NULL to derive it
2641
 * from the pszBaseFilename
2642
 * @param padfGeoTransform the six double array into which the
2643
 * geotransformation should be placed.
2644
 *
2645
 * @return TRUE on success or FALSE on failure.
2646
 */
2647
2648
int CPL_STDCALL GDALReadWorldFile(const char *pszBaseFilename,
2649
                                  const char *pszExtension,
2650
                                  double *padfGeoTransform)
2651
2652
117k
{
2653
117k
    return GDALReadWorldFile2(pszBaseFilename, pszExtension, padfGeoTransform,
2654
117k
                              nullptr, nullptr);
2655
117k
}
2656
2657
int GDALReadWorldFile2(const char *pszBaseFilename, const char *pszExtension,
2658
                       GDALGeoTransform &gt, CSLConstList papszSiblingFiles,
2659
                       char **ppszWorldFileNameOut)
2660
218k
{
2661
218k
    return GDALReadWorldFile2(pszBaseFilename, pszExtension, gt.data(),
2662
218k
                              papszSiblingFiles, ppszWorldFileNameOut);
2663
218k
}
2664
2665
int GDALReadWorldFile2(const char *pszBaseFilename, const char *pszExtension,
2666
                       double *padfGeoTransform, CSLConstList papszSiblingFiles,
2667
                       char **ppszWorldFileNameOut)
2668
595k
{
2669
595k
    VALIDATE_POINTER1(pszBaseFilename, "GDALReadWorldFile", FALSE);
2670
595k
    VALIDATE_POINTER1(padfGeoTransform, "GDALReadWorldFile", FALSE);
2671
2672
595k
    if (ppszWorldFileNameOut)
2673
360k
        *ppszWorldFileNameOut = nullptr;
2674
2675
595k
    if (!GDALCanFileAcceptSidecarFile(pszBaseFilename))
2676
1
        return FALSE;
2677
2678
    /* -------------------------------------------------------------------- */
2679
    /*      If we aren't given an extension, try both the unix and          */
2680
    /*      windows style extensions.                                       */
2681
    /* -------------------------------------------------------------------- */
2682
595k
    if (pszExtension == nullptr)
2683
167k
    {
2684
167k
        const std::string oBaseExt = CPLGetExtensionSafe(pszBaseFilename);
2685
2686
167k
        if (oBaseExt.length() < 2)
2687
38.3k
            return FALSE;
2688
2689
        // windows version - first + last + 'w'
2690
129k
        char szDerivedExtension[100] = {'\0'};
2691
129k
        szDerivedExtension[0] = oBaseExt[0];
2692
129k
        szDerivedExtension[1] = oBaseExt[oBaseExt.length() - 1];
2693
129k
        szDerivedExtension[2] = 'w';
2694
129k
        szDerivedExtension[3] = '\0';
2695
2696
129k
        if (GDALReadWorldFile2(pszBaseFilename, szDerivedExtension,
2697
129k
                               padfGeoTransform, papszSiblingFiles,
2698
129k
                               ppszWorldFileNameOut))
2699
53
            return TRUE;
2700
2701
        // unix version - extension + 'w'
2702
129k
        if (oBaseExt.length() > sizeof(szDerivedExtension) - 2)
2703
0
            return FALSE;
2704
2705
129k
        snprintf(szDerivedExtension, sizeof(szDerivedExtension), "%sw",
2706
129k
                 oBaseExt.c_str());
2707
129k
        return GDALReadWorldFile2(pszBaseFilename, szDerivedExtension,
2708
129k
                                  padfGeoTransform, papszSiblingFiles,
2709
129k
                                  ppszWorldFileNameOut);
2710
129k
    }
2711
2712
    /* -------------------------------------------------------------------- */
2713
    /*      Skip the leading period in the extension if there is one.       */
2714
    /* -------------------------------------------------------------------- */
2715
427k
    if (*pszExtension == '.')
2716
858
        pszExtension++;
2717
2718
    /* -------------------------------------------------------------------- */
2719
    /*      Generate upper and lower case versions of the extension.        */
2720
    /* -------------------------------------------------------------------- */
2721
427k
    char szExtUpper[32] = {'\0'};
2722
427k
    char szExtLower[32] = {'\0'};
2723
427k
    CPLStrlcpy(szExtUpper, pszExtension, sizeof(szExtUpper));
2724
427k
    CPLStrlcpy(szExtLower, pszExtension, sizeof(szExtLower));
2725
2726
1.83M
    for (int i = 0; szExtUpper[i] != '\0'; i++)
2727
1.41M
    {
2728
1.41M
        szExtUpper[i] = static_cast<char>(
2729
1.41M
            CPLToupper(static_cast<unsigned char>(szExtUpper[i])));
2730
1.41M
        szExtLower[i] = static_cast<char>(
2731
1.41M
            CPLTolower(static_cast<unsigned char>(szExtLower[i])));
2732
1.41M
    }
2733
2734
427k
    std::string osTFW = CPLResetExtensionSafe(pszBaseFilename, szExtLower);
2735
2736
427k
    if (papszSiblingFiles &&
2737
        // cppcheck-suppress knownConditionTrueFalse
2738
251k
        GDALCanReliablyUseSiblingFileList(osTFW.c_str()))
2739
251k
    {
2740
251k
        const int iSibling =
2741
251k
            CSLFindString(papszSiblingFiles, CPLGetFilename(osTFW.c_str()));
2742
251k
        if (iSibling >= 0)
2743
79
        {
2744
79
            CPLString osTFWFilename = pszBaseFilename;
2745
79
            osTFWFilename.resize(strlen(pszBaseFilename) -
2746
79
                                 strlen(CPLGetFilename(pszBaseFilename)));
2747
79
            osTFWFilename += papszSiblingFiles[iSibling];
2748
79
            if (GDALLoadWorldFile(osTFWFilename, padfGeoTransform))
2749
6
            {
2750
6
                if (ppszWorldFileNameOut)
2751
6
                    *ppszWorldFileNameOut = CPLStrdup(osTFWFilename);
2752
6
                return TRUE;
2753
6
            }
2754
79
        }
2755
251k
        return FALSE;
2756
251k
    }
2757
2758
    /* -------------------------------------------------------------------- */
2759
    /*      Try lower case, then upper case.                                */
2760
    /* -------------------------------------------------------------------- */
2761
2762
176k
    VSIStatBufL sStatBuf;
2763
176k
    bool bGotTFW =
2764
176k
        VSIStatExL(osTFW.c_str(), &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
2765
2766
176k
    if (!bGotTFW && VSIIsCaseSensitiveFS(osTFW.c_str()))
2767
175k
    {
2768
175k
        osTFW = CPLResetExtensionSafe(pszBaseFilename, szExtUpper);
2769
175k
        bGotTFW =
2770
175k
            VSIStatExL(osTFW.c_str(), &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
2771
175k
    }
2772
2773
176k
    if (!bGotTFW)
2774
175k
        return FALSE;
2775
2776
    /* -------------------------------------------------------------------- */
2777
    /*      We found the file, now load and parse it.                       */
2778
    /* -------------------------------------------------------------------- */
2779
713
    if (GDALLoadWorldFile(osTFW.c_str(), padfGeoTransform))
2780
108
    {
2781
108
        if (ppszWorldFileNameOut)
2782
0
            *ppszWorldFileNameOut = CPLStrdup(osTFW.c_str());
2783
108
        return TRUE;
2784
108
    }
2785
605
    return FALSE;
2786
713
}
2787
2788
/************************************************************************/
2789
/*                         GDALWriteWorldFile()                         */
2790
/*                                                                      */
2791
/*      Helper function for translator implementer wanting              */
2792
/*      support for ESRI world files.                                   */
2793
/************************************************************************/
2794
2795
/**
2796
 * \brief Write ESRI world file.
2797
 *
2798
 * This function writes an ESRI style world file from the passed geotransform.
2799
 *
2800
 * The world file contains an affine transformation with the parameters
2801
 * in a different order than in a geotransform array.
2802
 *
2803
 * <ul>
2804
 * <li> geotransform[1] : width of pixel</li>
2805
 * <li> geotransform[4] : rotational coefficient, zero for north up images.</li>
2806
 * <li> geotransform[2] : rotational coefficient, zero for north up images.</li>
2807
 * <li> geotransform[5] : height of pixel (but negative)</li>
2808
 * <li> geotransform[0] + 0.5 * geotransform[1] + 0.5 * geotransform[2] : x
2809
 * offset to center of top left pixel.</li>
2810
 * <li> geotransform[3] + 0.5 *
2811
 * geotransform[4] + 0.5 * geotransform[5] : y offset to center of top left
2812
 * pixel.</li>
2813
 * </ul>
2814
 *
2815
 * @param pszBaseFilename the target raster file.
2816
 * @param pszExtension the extension to use (i.e. "wld"). Must not be NULL
2817
 * @param padfGeoTransform the six double array from which the
2818
 * geotransformation should be read.
2819
 *
2820
 * @return TRUE on success or FALSE on failure.
2821
 */
2822
2823
int CPL_STDCALL GDALWriteWorldFile(const char *pszBaseFilename,
2824
                                   const char *pszExtension,
2825
                                   double *padfGeoTransform)
2826
2827
0
{
2828
0
    VALIDATE_POINTER1(pszBaseFilename, "GDALWriteWorldFile", FALSE);
2829
0
    VALIDATE_POINTER1(pszExtension, "GDALWriteWorldFile", FALSE);
2830
0
    VALIDATE_POINTER1(padfGeoTransform, "GDALWriteWorldFile", FALSE);
2831
2832
    /* -------------------------------------------------------------------- */
2833
    /*      Prepare the text to write to the file.                          */
2834
    /* -------------------------------------------------------------------- */
2835
0
    CPLString osTFWText;
2836
2837
0
    osTFWText.Printf("%.15f\n%.15f\n%.15f\n%.15f\n%.15f\n%.15f\n",
2838
0
                     padfGeoTransform[1], padfGeoTransform[4],
2839
0
                     padfGeoTransform[2], padfGeoTransform[5],
2840
0
                     padfGeoTransform[0] + 0.5 * padfGeoTransform[1] +
2841
0
                         0.5 * padfGeoTransform[2],
2842
0
                     padfGeoTransform[3] + 0.5 * padfGeoTransform[4] +
2843
0
                         0.5 * padfGeoTransform[5]);
2844
2845
    /* -------------------------------------------------------------------- */
2846
    /*      Update extension, and write to disk.                            */
2847
    /* -------------------------------------------------------------------- */
2848
0
    const std::string osTFW =
2849
0
        CPLResetExtensionSafe(pszBaseFilename, pszExtension);
2850
0
    VSILFILE *const fpTFW = VSIFOpenL(osTFW.c_str(), "wt");
2851
0
    if (fpTFW == nullptr)
2852
0
        return FALSE;
2853
2854
0
    const int bRet =
2855
0
        VSIFWriteL(osTFWText.c_str(), osTFWText.size(), 1, fpTFW) == 1;
2856
0
    if (VSIFCloseL(fpTFW) != 0)
2857
0
        return FALSE;
2858
2859
0
    return bRet;
2860
0
}
2861
2862
/************************************************************************/
2863
/*                          GDALVersionInfo()                           */
2864
/************************************************************************/
2865
2866
/**
2867
 * \brief Get runtime version information.
2868
 *
2869
 * Available pszRequest values:
2870
 * <ul>
2871
 * <li> "VERSION_NUM": Returns GDAL_VERSION_NUM formatted as a string.  i.e.
2872
 * "30603000", e.g for GDAL 3.6.3.0</li>
2873
 * <li> "RELEASE_DATE": Returns GDAL_RELEASE_DATE formatted as a
2874
 * string. i.e. "20230312".</li>
2875
 * <li> "RELEASE_NAME": Returns the GDAL_RELEASE_NAME. ie. "3.6.3"</li>
2876
 * <li> "RELEASE_NICKNAME": (>= 3.11) Returns the GDAL_RELEASE_NICKNAME.
2877
 * (may be empty)</li>
2878
 * <li> "\--version": Returns one line version message suitable for
2879
 * use in response to \--version requests.  i.e. "GDAL 3.6.3, released
2880
 * 2023/03/12"</li>
2881
 * <li> "LICENSE": Returns the content of the LICENSE.TXT file from
2882
 * the GDAL_DATA directory.
2883
 * </li>
2884
 * <li> "BUILD_INFO": List of NAME=VALUE pairs separated by newlines
2885
 * with information on build time options.</li>
2886
 * </ul>
2887
 *
2888
 * @param pszRequest the type of version info desired, as listed above.
2889
 *
2890
 * @return an internal string containing the requested information.
2891
 */
2892
2893
const char *CPL_STDCALL GDALVersionInfo(const char *pszRequest)
2894
2895
173
{
2896
    /* -------------------------------------------------------------------- */
2897
    /*      Try to capture as much build information as practical.          */
2898
    /* -------------------------------------------------------------------- */
2899
173
    if (pszRequest != nullptr && EQUAL(pszRequest, "BUILD_INFO"))
2900
0
    {
2901
0
        CPLString osBuildInfo;
2902
2903
0
#define STRINGIFY_HELPER(x) #x
2904
0
#define STRINGIFY(x) STRINGIFY_HELPER(x)
2905
2906
#ifdef ESRI_BUILD
2907
        osBuildInfo += "ESRI_BUILD=YES\n";
2908
#endif
2909
#ifdef PAM_ENABLED
2910
        osBuildInfo += "PAM_ENABLED=YES\n";
2911
#endif
2912
0
        osBuildInfo += "OGR_ENABLED=YES\n";  // Deprecated.  Always yes.
2913
0
#ifdef HAVE_CURL
2914
0
        osBuildInfo += "CURL_ENABLED=YES\n";
2915
0
        osBuildInfo += "CURL_VERSION=" LIBCURL_VERSION "\n";
2916
0
#endif
2917
#ifdef HAVE_GEOS
2918
        osBuildInfo += "GEOS_ENABLED=YES\n";
2919
#ifdef GEOS_CAPI_VERSION
2920
        osBuildInfo += "GEOS_VERSION=" GEOS_CAPI_VERSION "\n";
2921
#endif
2922
#endif
2923
0
        osBuildInfo +=
2924
0
            "PROJ_BUILD_VERSION=" STRINGIFY(PROJ_VERSION_MAJOR) "." STRINGIFY(
2925
0
                PROJ_VERSION_MINOR) "." STRINGIFY(PROJ_VERSION_PATCH) "\n";
2926
0
        osBuildInfo += "PROJ_RUNTIME_VERSION=";
2927
0
        osBuildInfo += proj_info().version;
2928
0
        osBuildInfo += '\n';
2929
2930
0
#ifdef __VERSION__
2931
0
#ifdef __clang_version__
2932
0
        osBuildInfo += "COMPILER=clang " __clang_version__ "\n";
2933
#elif defined(__GNUC__)
2934
        osBuildInfo += "COMPILER=GCC " __VERSION__ "\n";
2935
#elif defined(__INTEL_COMPILER)
2936
        osBuildInfo += "COMPILER=" __VERSION__ "\n";
2937
#else
2938
        // STRINGIFY() as we're not sure if its a int or a string
2939
        osBuildInfo += "COMPILER=unknown compiler " STRINGIFY(__VERSION__) "\n";
2940
#endif
2941
#elif defined(_MSC_FULL_VER)
2942
        osBuildInfo += "COMPILER=MSVC " STRINGIFY(_MSC_FULL_VER) "\n";
2943
#elif defined(__INTEL_COMPILER)
2944
        osBuildInfo +=
2945
            "COMPILER=Intel compiler " STRINGIFY(__INTEL_COMPILER) "\n";
2946
#endif
2947
#ifdef CMAKE_UNITY_BUILD
2948
        osBuildInfo += "CMAKE_UNITY_BUILD=YES\n";
2949
#endif
2950
0
#ifdef EMBED_RESOURCE_FILES
2951
0
        osBuildInfo += "EMBED_RESOURCE_FILES=YES\n";
2952
0
#endif
2953
#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES
2954
        osBuildInfo += "USE_ONLY_EMBEDDED_RESOURCE_FILES=YES\n";
2955
#endif
2956
#ifdef DEBUG
2957
        osBuildInfo += "DEBUG=YES\n";
2958
#endif
2959
0
#undef STRINGIFY_HELPER
2960
0
#undef STRINGIFY
2961
2962
0
        CPLFree(CPLGetTLS(CTLS_VERSIONINFO));
2963
0
        CPLSetTLS(CTLS_VERSIONINFO, CPLStrdup(osBuildInfo), TRUE);
2964
0
        return static_cast<char *>(CPLGetTLS(CTLS_VERSIONINFO));
2965
0
    }
2966
2967
    /* -------------------------------------------------------------------- */
2968
    /*      LICENSE is a special case. We try to find and read the          */
2969
    /*      LICENSE.TXT file from the GDAL_DATA directory and return it     */
2970
    /* -------------------------------------------------------------------- */
2971
173
    if (pszRequest != nullptr && EQUAL(pszRequest, "LICENSE"))
2972
0
    {
2973
#if defined(EMBED_RESOURCE_FILES) && defined(USE_ONLY_EMBEDDED_RESOURCE_FILES)
2974
        return GDALGetEmbeddedLicense();
2975
#else
2976
0
        char *pszResultLicence =
2977
0
            reinterpret_cast<char *>(CPLGetTLS(CTLS_VERSIONINFO_LICENCE));
2978
0
        if (pszResultLicence != nullptr)
2979
0
        {
2980
0
            return pszResultLicence;
2981
0
        }
2982
2983
0
        VSILFILE *fp = nullptr;
2984
0
#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES
2985
0
#ifdef EMBED_RESOURCE_FILES
2986
0
        CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
2987
0
#endif
2988
0
        const char *pszFilename = CPLFindFile("etc", "LICENSE.TXT");
2989
0
        if (pszFilename != nullptr)
2990
0
            fp = VSIFOpenL(pszFilename, "r");
2991
0
        if (fp != nullptr)
2992
0
        {
2993
0
            if (VSIFSeekL(fp, 0, SEEK_END) == 0)
2994
0
            {
2995
                // TODO(schwehr): Handle if VSITellL returns a value too large
2996
                // for size_t.
2997
0
                const size_t nLength = static_cast<size_t>(VSIFTellL(fp) + 1);
2998
0
                if (VSIFSeekL(fp, SEEK_SET, 0) == 0)
2999
0
                {
3000
0
                    pszResultLicence =
3001
0
                        static_cast<char *>(VSICalloc(1, nLength));
3002
0
                    if (pszResultLicence)
3003
0
                        CPL_IGNORE_RET_VAL(
3004
0
                            VSIFReadL(pszResultLicence, 1, nLength - 1, fp));
3005
0
                }
3006
0
            }
3007
3008
0
            CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
3009
0
        }
3010
0
#endif
3011
3012
0
#ifdef EMBED_RESOURCE_FILES
3013
0
        if (!fp)
3014
0
        {
3015
0
            return GDALGetEmbeddedLicense();
3016
0
        }
3017
0
#endif
3018
3019
0
        if (!pszResultLicence)
3020
0
        {
3021
0
            pszResultLicence =
3022
0
                CPLStrdup("GDAL/OGR is released under the MIT license.\n"
3023
0
                          "The LICENSE.TXT distributed with GDAL/OGR should\n"
3024
0
                          "contain additional details.\n");
3025
0
        }
3026
3027
0
        CPLSetTLS(CTLS_VERSIONINFO_LICENCE, pszResultLicence, TRUE);
3028
0
        return pszResultLicence;
3029
0
#endif
3030
0
    }
3031
3032
    /* -------------------------------------------------------------------- */
3033
    /*      All other strings are fairly small.                             */
3034
    /* -------------------------------------------------------------------- */
3035
173
    CPLString osVersionInfo;
3036
3037
173
    if (pszRequest == nullptr || EQUAL(pszRequest, "VERSION_NUM"))
3038
0
        osVersionInfo.Printf("%d", GDAL_VERSION_NUM);
3039
173
    else if (EQUAL(pszRequest, "RELEASE_DATE"))
3040
0
        osVersionInfo.Printf("%d", GDAL_RELEASE_DATE);
3041
173
    else if (EQUAL(pszRequest, "RELEASE_NAME"))
3042
173
        osVersionInfo.Printf(GDAL_RELEASE_NAME);
3043
0
    else if (EQUAL(pszRequest, "RELEASE_NICKNAME"))
3044
0
        osVersionInfo.Printf("%s", GDAL_RELEASE_NICKNAME);
3045
0
    else  // --version
3046
0
    {
3047
0
        osVersionInfo = "GDAL " GDAL_RELEASE_NAME;
3048
        if constexpr (GDAL_RELEASE_NICKNAME[0] != '\0')
3049
        {
3050
            osVersionInfo += " \"" GDAL_RELEASE_NICKNAME "\"";
3051
        }
3052
0
        osVersionInfo += CPLString().Printf(
3053
0
            ", released %d/%02d/%02d", GDAL_RELEASE_DATE / 10000,
3054
0
            (GDAL_RELEASE_DATE % 10000) / 100, GDAL_RELEASE_DATE % 100);
3055
#if defined(__GNUC__) && !defined(__OPTIMIZE__)
3056
        // Cf https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
3057
        // also true for CLang
3058
        osVersionInfo += " (debug build)";
3059
#elif defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 2
3060
        // https://docs.microsoft.com/en-us/cpp/standard-library/iterator-debug-level?view=msvc-170
3061
        // In release mode, the compiler generates an error if you specify
3062
        // _ITERATOR_DEBUG_LEVEL as 2.
3063
        osVersionInfo += " (debug build)";
3064
#endif
3065
0
    }
3066
3067
173
    CPLFree(CPLGetTLS(CTLS_VERSIONINFO));  // clear old value.
3068
173
    CPLSetTLS(CTLS_VERSIONINFO, CPLStrdup(osVersionInfo), TRUE);
3069
173
    return static_cast<char *>(CPLGetTLS(CTLS_VERSIONINFO));
3070
173
}
3071
3072
/************************************************************************/
3073
/*                          GDALCheckVersion()                          */
3074
/************************************************************************/
3075
3076
/** Return TRUE if GDAL library version at runtime matches
3077
   nVersionMajor.nVersionMinor.
3078
3079
    The purpose of this method is to ensure that calling code will run
3080
    with the GDAL version it is compiled for. It is primarily intended
3081
    for external plugins.
3082
3083
    @param nVersionMajor Major version to be tested against
3084
    @param nVersionMinor Minor version to be tested against
3085
    @param pszCallingComponentName If not NULL, in case of version mismatch, the
3086
   method will issue a failure mentioning the name of the calling component.
3087
3088
    @return TRUE if GDAL library version at runtime matches
3089
    nVersionMajor.nVersionMinor, FALSE otherwise.
3090
  */
3091
int CPL_STDCALL GDALCheckVersion(int nVersionMajor, int nVersionMinor,
3092
                                 const char *pszCallingComponentName)
3093
398
{
3094
398
    if (nVersionMajor == GDAL_VERSION_MAJOR &&
3095
398
        nVersionMinor == GDAL_VERSION_MINOR)
3096
398
        return TRUE;
3097
3098
0
    if (pszCallingComponentName)
3099
0
    {
3100
0
        CPLError(CE_Failure, CPLE_AppDefined,
3101
0
                 "%s was compiled against GDAL %d.%d, but "
3102
0
                 "the current library version is %d.%d",
3103
0
                 pszCallingComponentName, nVersionMajor, nVersionMinor,
3104
0
                 GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
3105
0
    }
3106
0
    return FALSE;
3107
398
}
3108
3109
/************************************************************************/
3110
/*                            GDALDecToDMS()                            */
3111
/************************************************************************/
3112
3113
/** Translate a decimal degrees value to a DMS string with hemisphere.
3114
 */
3115
const char *CPL_STDCALL GDALDecToDMS(double dfAngle, const char *pszAxis,
3116
                                     int nPrecision)
3117
3118
0
{
3119
0
    return CPLDecToDMS(dfAngle, pszAxis, nPrecision);
3120
0
}
3121
3122
/************************************************************************/
3123
/*                         GDALPackedDMSToDec()                         */
3124
/************************************************************************/
3125
3126
/**
3127
 * \brief Convert a packed DMS value (DDDMMMSSS.SS) into decimal degrees.
3128
 *
3129
 * See CPLPackedDMSToDec().
3130
 */
3131
3132
double CPL_STDCALL GDALPackedDMSToDec(double dfPacked)
3133
3134
0
{
3135
0
    return CPLPackedDMSToDec(dfPacked);
3136
0
}
3137
3138
/************************************************************************/
3139
/*                         GDALDecToPackedDMS()                         */
3140
/************************************************************************/
3141
3142
/**
3143
 * \brief Convert decimal degrees into packed DMS value (DDDMMMSSS.SS).
3144
 *
3145
 * See CPLDecToPackedDMS().
3146
 */
3147
3148
double CPL_STDCALL GDALDecToPackedDMS(double dfDec)
3149
3150
0
{
3151
0
    return CPLDecToPackedDMS(dfDec);
3152
0
}
3153
3154
/************************************************************************/
3155
/*                       GDALGCPsToGeoTransform()                       */
3156
/************************************************************************/
3157
3158
/**
3159
 * \brief Generate Geotransform from GCPs.
3160
 *
3161
 * Given a set of GCPs perform first order fit as a geotransform.
3162
 *
3163
 * Due to imprecision in the calculations the fit algorithm will often
3164
 * return non-zero rotational coefficients even if given perfectly non-rotated
3165
 * inputs.  A special case has been implemented for corner corner coordinates
3166
 * given in TL, TR, BR, BL order.  So when using this to get a geotransform
3167
 * from 4 corner coordinates, pass them in this order.
3168
 *
3169
 * If bApproxOK = FALSE, the
3170
 * GDAL_GCPS_TO_GEOTRANSFORM_APPROX_OK configuration option will be read. If
3171
 * set to YES, then bApproxOK will be overridden with TRUE.
3172
 * When exact fit is asked, the
3173
 * GDAL_GCPS_TO_GEOTRANSFORM_APPROX_THRESHOLD configuration option can be set to
3174
 * give the maximum error threshold in pixel. The default is 0.25.
3175
 *
3176
 * @param nGCPCount the number of GCPs being passed in.
3177
 * @param pasGCPs the list of GCP structures.
3178
 * @param padfGeoTransform the six double array in which the affine
3179
 * geotransformation will be returned.
3180
 * @param bApproxOK If FALSE the function will fail if the geotransform is not
3181
 * essentially an exact fit (within 0.25 pixel) for all GCPs.
3182
 *
3183
 * @return TRUE on success or FALSE if there aren't enough points to prepare a
3184
 * geotransform, the pointers are ill-determined or if bApproxOK is FALSE
3185
 * and the fit is poor.
3186
 */
3187
3188
// TODO(schwehr): Add consts to args.
3189
int CPL_STDCALL GDALGCPsToGeoTransform(int nGCPCount, const GDAL_GCP *pasGCPs,
3190
                                       double *padfGeoTransform, int bApproxOK)
3191
3192
4.12k
{
3193
4.12k
    double dfPixelThreshold = 0.25;
3194
4.12k
    if (!bApproxOK)
3195
2.86k
    {
3196
2.86k
        bApproxOK = CPLTestBool(
3197
2.86k
            CPLGetConfigOption("GDAL_GCPS_TO_GEOTRANSFORM_APPROX_OK", "NO"));
3198
2.86k
        if (!bApproxOK)
3199
2.86k
        {
3200
2.86k
            dfPixelThreshold = std::clamp(
3201
2.86k
                CPLAtof(CPLGetConfigOption(
3202
2.86k
                    "GDAL_GCPS_TO_GEOTRANSFORM_APPROX_THRESHOLD", "0.25")),
3203
2.86k
                0.0, std::numeric_limits<double>::max());
3204
2.86k
        }
3205
2.86k
    }
3206
3207
    /* -------------------------------------------------------------------- */
3208
    /*      Recognise a few special cases.                                  */
3209
    /* -------------------------------------------------------------------- */
3210
4.12k
    if (nGCPCount < 2)
3211
35
        return FALSE;
3212
3213
4.08k
    if (nGCPCount == 2)
3214
2
    {
3215
2
        if (pasGCPs[1].dfGCPPixel == pasGCPs[0].dfGCPPixel ||
3216
2
            pasGCPs[1].dfGCPLine == pasGCPs[0].dfGCPLine)
3217
0
            return FALSE;
3218
3219
2
        padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX) /
3220
2
                              (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
3221
2
        padfGeoTransform[2] = 0.0;
3222
3223
2
        padfGeoTransform[4] = 0.0;
3224
2
        padfGeoTransform[5] = (pasGCPs[1].dfGCPY - pasGCPs[0].dfGCPY) /
3225
2
                              (pasGCPs[1].dfGCPLine - pasGCPs[0].dfGCPLine);
3226
3227
2
        padfGeoTransform[0] = pasGCPs[0].dfGCPX -
3228
2
                              pasGCPs[0].dfGCPPixel * padfGeoTransform[1] -
3229
2
                              pasGCPs[0].dfGCPLine * padfGeoTransform[2];
3230
3231
2
        padfGeoTransform[3] = pasGCPs[0].dfGCPY -
3232
2
                              pasGCPs[0].dfGCPPixel * padfGeoTransform[4] -
3233
2
                              pasGCPs[0].dfGCPLine * padfGeoTransform[5];
3234
3235
2
        return TRUE;
3236
2
    }
3237
3238
    /* -------------------------------------------------------------------- */
3239
    /*      Special case of 4 corner coordinates of a non-rotated           */
3240
    /*      image.  The points must be in TL-TR-BR-BL order for now.        */
3241
    /*      This case helps avoid some imprecision in the general           */
3242
    /*      calculations.                                                   */
3243
    /* -------------------------------------------------------------------- */
3244
4.08k
    if (nGCPCount == 4 && pasGCPs[0].dfGCPLine == pasGCPs[1].dfGCPLine &&
3245
1.59k
        pasGCPs[2].dfGCPLine == pasGCPs[3].dfGCPLine &&
3246
935
        pasGCPs[0].dfGCPPixel == pasGCPs[3].dfGCPPixel &&
3247
297
        pasGCPs[1].dfGCPPixel == pasGCPs[2].dfGCPPixel &&
3248
297
        pasGCPs[0].dfGCPLine != pasGCPs[2].dfGCPLine &&
3249
119
        pasGCPs[0].dfGCPPixel != pasGCPs[1].dfGCPPixel &&
3250
89
        pasGCPs[0].dfGCPY == pasGCPs[1].dfGCPY &&
3251
69
        pasGCPs[2].dfGCPY == pasGCPs[3].dfGCPY &&
3252
65
        pasGCPs[0].dfGCPX == pasGCPs[3].dfGCPX &&
3253
63
        pasGCPs[1].dfGCPX == pasGCPs[2].dfGCPX &&
3254
62
        pasGCPs[0].dfGCPY != pasGCPs[2].dfGCPY &&
3255
16
        pasGCPs[0].dfGCPX != pasGCPs[1].dfGCPX)
3256
16
    {
3257
16
        padfGeoTransform[1] = (pasGCPs[1].dfGCPX - pasGCPs[0].dfGCPX) /
3258
16
                              (pasGCPs[1].dfGCPPixel - pasGCPs[0].dfGCPPixel);
3259
16
        padfGeoTransform[2] = 0.0;
3260
16
        padfGeoTransform[4] = 0.0;
3261
16
        padfGeoTransform[5] = (pasGCPs[2].dfGCPY - pasGCPs[1].dfGCPY) /
3262
16
                              (pasGCPs[2].dfGCPLine - pasGCPs[1].dfGCPLine);
3263
3264
16
        padfGeoTransform[0] =
3265
16
            pasGCPs[0].dfGCPX - pasGCPs[0].dfGCPPixel * padfGeoTransform[1];
3266
16
        padfGeoTransform[3] =
3267
16
            pasGCPs[0].dfGCPY - pasGCPs[0].dfGCPLine * padfGeoTransform[5];
3268
16
        return TRUE;
3269
16
    }
3270
3271
    /* -------------------------------------------------------------------- */
3272
    /*      Compute source and destination ranges so we can normalize       */
3273
    /*      the values to make the least squares computation more stable.   */
3274
    /* -------------------------------------------------------------------- */
3275
4.06k
    double min_pixel = pasGCPs[0].dfGCPPixel;
3276
4.06k
    double max_pixel = pasGCPs[0].dfGCPPixel;
3277
4.06k
    double min_line = pasGCPs[0].dfGCPLine;
3278
4.06k
    double max_line = pasGCPs[0].dfGCPLine;
3279
4.06k
    double min_geox = pasGCPs[0].dfGCPX;
3280
4.06k
    double max_geox = pasGCPs[0].dfGCPX;
3281
4.06k
    double min_geoy = pasGCPs[0].dfGCPY;
3282
4.06k
    double max_geoy = pasGCPs[0].dfGCPY;
3283
3284
19.2k
    for (int i = 1; i < nGCPCount; ++i)
3285
15.2k
    {
3286
15.2k
        min_pixel = std::min(min_pixel, pasGCPs[i].dfGCPPixel);
3287
15.2k
        max_pixel = std::max(max_pixel, pasGCPs[i].dfGCPPixel);
3288
15.2k
        min_line = std::min(min_line, pasGCPs[i].dfGCPLine);
3289
15.2k
        max_line = std::max(max_line, pasGCPs[i].dfGCPLine);
3290
15.2k
        min_geox = std::min(min_geox, pasGCPs[i].dfGCPX);
3291
15.2k
        max_geox = std::max(max_geox, pasGCPs[i].dfGCPX);
3292
15.2k
        min_geoy = std::min(min_geoy, pasGCPs[i].dfGCPY);
3293
15.2k
        max_geoy = std::max(max_geoy, pasGCPs[i].dfGCPY);
3294
15.2k
    }
3295
3296
4.06k
    double EPS = 1.0e-12;
3297
3298
4.06k
    if (std::abs(max_pixel - min_pixel) < EPS ||
3299
3.84k
        std::abs(max_line - min_line) < EPS ||
3300
3.80k
        std::abs(max_geox - min_geox) < EPS ||
3301
3.74k
        std::abs(max_geoy - min_geoy) < EPS)
3302
341
    {
3303
341
        return FALSE;  // degenerate in at least one dimension.
3304
341
    }
3305
3306
3.72k
    double pl_normalize[6], geo_normalize[6];
3307
3308
3.72k
    pl_normalize[0] = -min_pixel / (max_pixel - min_pixel);
3309
3.72k
    pl_normalize[1] = 1.0 / (max_pixel - min_pixel);
3310
3.72k
    pl_normalize[2] = 0.0;
3311
3.72k
    pl_normalize[3] = -min_line / (max_line - min_line);
3312
3.72k
    pl_normalize[4] = 0.0;
3313
3.72k
    pl_normalize[5] = 1.0 / (max_line - min_line);
3314
3315
3.72k
    geo_normalize[0] = -min_geox / (max_geox - min_geox);
3316
3.72k
    geo_normalize[1] = 1.0 / (max_geox - min_geox);
3317
3.72k
    geo_normalize[2] = 0.0;
3318
3.72k
    geo_normalize[3] = -min_geoy / (max_geoy - min_geoy);
3319
3.72k
    geo_normalize[4] = 0.0;
3320
3.72k
    geo_normalize[5] = 1.0 / (max_geoy - min_geoy);
3321
3322
    /* -------------------------------------------------------------------- */
3323
    /* In the general case, do a least squares error approximation by       */
3324
    /* solving the equation Sum[(A - B*x + C*y - Lon)^2] = minimum          */
3325
    /* -------------------------------------------------------------------- */
3326
3327
3.72k
    double sum_x = 0.0;
3328
3.72k
    double sum_y = 0.0;
3329
3.72k
    double sum_xy = 0.0;
3330
3.72k
    double sum_xx = 0.0;
3331
3.72k
    double sum_yy = 0.0;
3332
3.72k
    double sum_Lon = 0.0;
3333
3.72k
    double sum_Lonx = 0.0;
3334
3.72k
    double sum_Lony = 0.0;
3335
3.72k
    double sum_Lat = 0.0;
3336
3.72k
    double sum_Latx = 0.0;
3337
3.72k
    double sum_Laty = 0.0;
3338
3339
21.6k
    for (int i = 0; i < nGCPCount; ++i)
3340
17.9k
    {
3341
17.9k
        double pixel, line, geox, geoy;
3342
3343
17.9k
        GDALApplyGeoTransform(pl_normalize, pasGCPs[i].dfGCPPixel,
3344
17.9k
                              pasGCPs[i].dfGCPLine, &pixel, &line);
3345
17.9k
        GDALApplyGeoTransform(geo_normalize, pasGCPs[i].dfGCPX,
3346
17.9k
                              pasGCPs[i].dfGCPY, &geox, &geoy);
3347
3348
17.9k
        sum_x += pixel;
3349
17.9k
        sum_y += line;
3350
17.9k
        sum_xy += pixel * line;
3351
17.9k
        sum_xx += pixel * pixel;
3352
17.9k
        sum_yy += line * line;
3353
17.9k
        sum_Lon += geox;
3354
17.9k
        sum_Lonx += geox * pixel;
3355
17.9k
        sum_Lony += geox * line;
3356
17.9k
        sum_Lat += geoy;
3357
17.9k
        sum_Latx += geoy * pixel;
3358
17.9k
        sum_Laty += geoy * line;
3359
17.9k
    }
3360
3361
3.72k
    const double divisor = nGCPCount * (sum_xx * sum_yy - sum_xy * sum_xy) +
3362
3.72k
                           2 * sum_x * sum_y * sum_xy - sum_y * sum_y * sum_xx -
3363
3.72k
                           sum_x * sum_x * sum_yy;
3364
3365
    /* -------------------------------------------------------------------- */
3366
    /*      If the divisor is zero, there is no valid solution.             */
3367
    /* -------------------------------------------------------------------- */
3368
3.72k
    if (divisor == 0.0)
3369
382
        return FALSE;
3370
3371
    /* -------------------------------------------------------------------- */
3372
    /*      Compute top/left origin.                                        */
3373
    /* -------------------------------------------------------------------- */
3374
3.34k
    double gt_normalized[6] = {0.0};
3375
3.34k
    gt_normalized[0] = (sum_Lon * (sum_xx * sum_yy - sum_xy * sum_xy) +
3376
3.34k
                        sum_Lonx * (sum_y * sum_xy - sum_x * sum_yy) +
3377
3.34k
                        sum_Lony * (sum_x * sum_xy - sum_y * sum_xx)) /
3378
3.34k
                       divisor;
3379
3380
3.34k
    gt_normalized[3] = (sum_Lat * (sum_xx * sum_yy - sum_xy * sum_xy) +
3381
3.34k
                        sum_Latx * (sum_y * sum_xy - sum_x * sum_yy) +
3382
3.34k
                        sum_Laty * (sum_x * sum_xy - sum_y * sum_xx)) /
3383
3.34k
                       divisor;
3384
3385
    /* -------------------------------------------------------------------- */
3386
    /*      Compute X related coefficients.                                 */
3387
    /* -------------------------------------------------------------------- */
3388
3.34k
    gt_normalized[1] = (sum_Lon * (sum_y * sum_xy - sum_x * sum_yy) +
3389
3.34k
                        sum_Lonx * (nGCPCount * sum_yy - sum_y * sum_y) +
3390
3.34k
                        sum_Lony * (sum_x * sum_y - sum_xy * nGCPCount)) /
3391
3.34k
                       divisor;
3392
3393
3.34k
    gt_normalized[2] = (sum_Lon * (sum_x * sum_xy - sum_y * sum_xx) +
3394
3.34k
                        sum_Lonx * (sum_x * sum_y - nGCPCount * sum_xy) +
3395
3.34k
                        sum_Lony * (nGCPCount * sum_xx - sum_x * sum_x)) /
3396
3.34k
                       divisor;
3397
3398
    /* -------------------------------------------------------------------- */
3399
    /*      Compute Y related coefficients.                                 */
3400
    /* -------------------------------------------------------------------- */
3401
3.34k
    gt_normalized[4] = (sum_Lat * (sum_y * sum_xy - sum_x * sum_yy) +
3402
3.34k
                        sum_Latx * (nGCPCount * sum_yy - sum_y * sum_y) +
3403
3.34k
                        sum_Laty * (sum_x * sum_y - sum_xy * nGCPCount)) /
3404
3.34k
                       divisor;
3405
3406
3.34k
    gt_normalized[5] = (sum_Lat * (sum_x * sum_xy - sum_y * sum_xx) +
3407
3.34k
                        sum_Latx * (sum_x * sum_y - nGCPCount * sum_xy) +
3408
3.34k
                        sum_Laty * (nGCPCount * sum_xx - sum_x * sum_x)) /
3409
3.34k
                       divisor;
3410
3411
    /* -------------------------------------------------------------------- */
3412
    /*      Compose the resulting transformation with the normalization     */
3413
    /*      geotransformations.                                             */
3414
    /* -------------------------------------------------------------------- */
3415
3.34k
    double gt1p2[6] = {0.0};
3416
3.34k
    double inv_geo_normalize[6] = {0.0};
3417
3.34k
    if (!GDALInvGeoTransform(geo_normalize, inv_geo_normalize))
3418
2
        return FALSE;
3419
3420
3.34k
    GDALComposeGeoTransforms(pl_normalize, gt_normalized, gt1p2);
3421
3.34k
    GDALComposeGeoTransforms(gt1p2, inv_geo_normalize, padfGeoTransform);
3422
3423
    // "Hour-glass" like shape of GCPs. Cf https://github.com/OSGeo/gdal/issues/11618
3424
3.34k
    if (std::abs(padfGeoTransform[1]) <= 1e-15 ||
3425
3.32k
        std::abs(padfGeoTransform[5]) <= 1e-15)
3426
607
    {
3427
607
        return FALSE;
3428
607
    }
3429
3430
    /* -------------------------------------------------------------------- */
3431
    /*      Now check if any of the input points fit this poorly.           */
3432
    /* -------------------------------------------------------------------- */
3433
2.73k
    if (!bApproxOK)
3434
2.02k
    {
3435
        // FIXME? Not sure if it is the more accurate way of computing
3436
        // pixel size
3437
2.02k
        double dfPixelSize =
3438
2.02k
            0.5 *
3439
2.02k
            (std::abs(padfGeoTransform[1]) + std::abs(padfGeoTransform[2]) +
3440
2.02k
             std::abs(padfGeoTransform[4]) + std::abs(padfGeoTransform[5]));
3441
2.02k
        if (dfPixelSize == 0.0)
3442
0
        {
3443
0
            CPLDebug("GDAL", "dfPixelSize = 0");
3444
0
            return FALSE;
3445
0
        }
3446
3447
7.21k
        for (int i = 0; i < nGCPCount; i++)
3448
5.94k
        {
3449
5.94k
            const double dfErrorX =
3450
5.94k
                (pasGCPs[i].dfGCPPixel * padfGeoTransform[1] +
3451
5.94k
                 pasGCPs[i].dfGCPLine * padfGeoTransform[2] +
3452
5.94k
                 padfGeoTransform[0]) -
3453
5.94k
                pasGCPs[i].dfGCPX;
3454
5.94k
            const double dfErrorY =
3455
5.94k
                (pasGCPs[i].dfGCPPixel * padfGeoTransform[4] +
3456
5.94k
                 pasGCPs[i].dfGCPLine * padfGeoTransform[5] +
3457
5.94k
                 padfGeoTransform[3]) -
3458
5.94k
                pasGCPs[i].dfGCPY;
3459
3460
5.94k
            if (std::abs(dfErrorX) > dfPixelThreshold * dfPixelSize ||
3461
5.40k
                std::abs(dfErrorY) > dfPixelThreshold * dfPixelSize)
3462
747
            {
3463
747
                CPLDebug("GDAL",
3464
747
                         "dfErrorX/dfPixelSize = %.2f, "
3465
747
                         "dfErrorY/dfPixelSize = %.2f",
3466
747
                         std::abs(dfErrorX) / dfPixelSize,
3467
747
                         std::abs(dfErrorY) / dfPixelSize);
3468
747
                return FALSE;
3469
747
            }
3470
5.94k
        }
3471
2.02k
    }
3472
3473
1.99k
    return TRUE;
3474
2.73k
}
3475
3476
/************************************************************************/
3477
/*                      GDALComposeGeoTransforms()                      */
3478
/************************************************************************/
3479
3480
/**
3481
 * \brief Compose two geotransforms.
3482
 *
3483
 * The resulting geotransform is the equivalent to padfGT1 and then padfGT2
3484
 * being applied to a point.
3485
 *
3486
 * @param padfGT1 the first geotransform, six values.
3487
 * @param padfGT2 the second geotransform, six values.
3488
 * @param padfGTOut the output geotransform, six values, may safely be the same
3489
 * array as padfGT1 or padfGT2.
3490
 */
3491
3492
void GDALComposeGeoTransforms(const double *padfGT1, const double *padfGT2,
3493
                              double *padfGTOut)
3494
3495
6.68k
{
3496
6.68k
    double gtwrk[6] = {0.0};
3497
    // We need to think of the geotransform in a more normal form to do
3498
    // the matrix multiple:
3499
    //
3500
    //  __                                __
3501
    //  | gt.xscale   gt.xrot     gt.xorig |
3502
    //  | gt.yrot     gt.yscale   gt.yorig |
3503
    //  |  0.0        0.0         1.0      |
3504
    //  --                                --
3505
    //
3506
    // Then we can use normal matrix multiplication to produce the
3507
    // composed transformation.  I don't actually reform the matrix
3508
    // explicitly which is why the following may seem kind of spagettish.
3509
3510
6.68k
    gtwrk[1] = padfGT2[1] * padfGT1[1] + padfGT2[2] * padfGT1[4];
3511
6.68k
    gtwrk[2] = padfGT2[1] * padfGT1[2] + padfGT2[2] * padfGT1[5];
3512
6.68k
    gtwrk[0] =
3513
6.68k
        padfGT2[1] * padfGT1[0] + padfGT2[2] * padfGT1[3] + padfGT2[0] * 1.0;
3514
3515
6.68k
    gtwrk[4] = padfGT2[4] * padfGT1[1] + padfGT2[5] * padfGT1[4];
3516
6.68k
    gtwrk[5] = padfGT2[4] * padfGT1[2] + padfGT2[5] * padfGT1[5];
3517
6.68k
    gtwrk[3] =
3518
6.68k
        padfGT2[4] * padfGT1[0] + padfGT2[5] * padfGT1[3] + padfGT2[3] * 1.0;
3519
6.68k
    memcpy(padfGTOut, gtwrk, sizeof(gtwrk));
3520
6.68k
}
3521
3522
/************************************************************************/
3523
/*                       StripIrrelevantOptions()                       */
3524
/************************************************************************/
3525
3526
static void StripIrrelevantOptions(CPLXMLNode *psCOL, int nOptions)
3527
0
{
3528
0
    if (psCOL == nullptr)
3529
0
        return;
3530
0
    if (nOptions == 0)
3531
0
        nOptions = GDAL_OF_RASTER;
3532
0
    if ((nOptions & GDAL_OF_RASTER) != 0 && (nOptions & GDAL_OF_VECTOR) != 0)
3533
0
        return;
3534
3535
0
    CPLXMLNode *psPrev = nullptr;
3536
0
    for (CPLXMLNode *psIter = psCOL->psChild; psIter;)
3537
0
    {
3538
0
        if (psIter->eType == CXT_Element)
3539
0
        {
3540
0
            CPLXMLNode *psScope = CPLGetXMLNode(psIter, "scope");
3541
0
            bool bStrip = false;
3542
0
            if (nOptions == GDAL_OF_RASTER && psScope && psScope->psChild &&
3543
0
                psScope->psChild->pszValue &&
3544
0
                EQUAL(psScope->psChild->pszValue, "vector"))
3545
0
            {
3546
0
                bStrip = true;
3547
0
            }
3548
0
            else if (nOptions == GDAL_OF_VECTOR && psScope &&
3549
0
                     psScope->psChild && psScope->psChild->pszValue &&
3550
0
                     EQUAL(psScope->psChild->pszValue, "raster"))
3551
0
            {
3552
0
                bStrip = true;
3553
0
            }
3554
0
            if (psScope)
3555
0
            {
3556
0
                CPLRemoveXMLChild(psIter, psScope);
3557
0
                CPLDestroyXMLNode(psScope);
3558
0
            }
3559
3560
0
            CPLXMLNode *psNext = psIter->psNext;
3561
0
            if (bStrip)
3562
0
            {
3563
0
                if (psPrev)
3564
0
                    psPrev->psNext = psNext;
3565
0
                else if (psCOL->psChild == psIter)
3566
0
                    psCOL->psChild = psNext;
3567
0
                psIter->psNext = nullptr;
3568
0
                CPLDestroyXMLNode(psIter);
3569
0
                psIter = psNext;
3570
0
            }
3571
0
            else
3572
0
            {
3573
0
                psPrev = psIter;
3574
0
                psIter = psNext;
3575
0
            }
3576
0
        }
3577
0
        else
3578
0
        {
3579
0
            psIter = psIter->psNext;
3580
0
        }
3581
0
    }
3582
0
}
3583
3584
/************************************************************************/
3585
/*                        GDALPrintDriverList()                         */
3586
/************************************************************************/
3587
3588
/** Print on stdout the driver list */
3589
std::string GDALPrintDriverList(int nOptions, bool bJSON)
3590
0
{
3591
0
    if (nOptions == 0)
3592
0
        nOptions = GDAL_OF_RASTER;
3593
3594
0
    if (bJSON)
3595
0
    {
3596
0
        auto poDM = GetGDALDriverManager();
3597
0
        CPLJSONArray oArray;
3598
0
        const int nDriverCount = poDM->GetDriverCount();
3599
0
        for (int iDr = 0; iDr < nDriverCount; ++iDr)
3600
0
        {
3601
0
            auto poDriver = poDM->GetDriver(iDr);
3602
0
            CSLConstList papszMD = poDriver->GetMetadata();
3603
3604
0
            if (nOptions == GDAL_OF_RASTER &&
3605
0
                !CPLFetchBool(papszMD, GDAL_DCAP_RASTER, false))
3606
0
                continue;
3607
0
            if (nOptions == GDAL_OF_VECTOR &&
3608
0
                !CPLFetchBool(papszMD, GDAL_DCAP_VECTOR, false))
3609
0
                continue;
3610
0
            if (nOptions == GDAL_OF_GNM &&
3611
0
                !CPLFetchBool(papszMD, GDAL_DCAP_GNM, false))
3612
0
                continue;
3613
0
            if (nOptions == GDAL_OF_MULTIDIM_RASTER &&
3614
0
                !CPLFetchBool(papszMD, GDAL_DCAP_MULTIDIM_RASTER, false))
3615
0
                continue;
3616
3617
0
            CPLJSONObject oJDriver;
3618
0
            oJDriver.Set("short_name", poDriver->GetDescription());
3619
0
            if (const char *pszLongName =
3620
0
                    CSLFetchNameValue(papszMD, GDAL_DMD_LONGNAME))
3621
0
                oJDriver.Set("long_name", pszLongName);
3622
0
            CPLJSONArray oJScopes;
3623
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_RASTER, false))
3624
0
                oJScopes.Add("raster");
3625
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_MULTIDIM_RASTER, false))
3626
0
                oJScopes.Add("multidimensional_raster");
3627
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_VECTOR, false))
3628
0
                oJScopes.Add("vector");
3629
0
            oJDriver.Add("scopes", oJScopes);
3630
0
            CPLJSONArray oJCaps;
3631
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_OPEN, false))
3632
0
                oJCaps.Add("open");
3633
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_CREATE, false))
3634
0
                oJCaps.Add("create");
3635
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_CREATECOPY, false))
3636
0
                oJCaps.Add("create_copy");
3637
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_UPDATE, false))
3638
0
                oJCaps.Add("update");
3639
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_VIRTUALIO, false))
3640
0
                oJCaps.Add("virtual_io");
3641
0
            oJDriver.Add("capabilities", oJCaps);
3642
3643
0
            if (const char *pszExtensions = CSLFetchNameValueDef(
3644
0
                    papszMD, GDAL_DMD_EXTENSIONS,
3645
0
                    CSLFetchNameValue(papszMD, GDAL_DMD_EXTENSION)))
3646
0
            {
3647
0
                const CPLStringList aosExt(
3648
0
                    CSLTokenizeString2(pszExtensions, " ", 0));
3649
0
                CPLJSONArray oJExts;
3650
0
                for (int i = 0; i < aosExt.size(); ++i)
3651
0
                {
3652
0
                    oJExts.Add(aosExt[i]);
3653
0
                }
3654
0
                oJDriver.Add("file_extensions", oJExts);
3655
0
            }
3656
3657
0
            oArray.Add(oJDriver);
3658
0
        }
3659
3660
0
        return oArray.Format(CPLJSONObject::PrettyFormat::Pretty);
3661
0
    }
3662
3663
0
    std::string ret;
3664
0
    ret = "Supported Formats: (ro:read-only, rw:read-write, "
3665
0
          "+:write from scratch, u:update, "
3666
0
          "v:virtual-I/O s:subdatasets)\n";
3667
0
    for (int iDr = 0; iDr < GDALGetDriverCount(); iDr++)
3668
0
    {
3669
0
        GDALDriverH hDriver = GDALGetDriver(iDr);
3670
3671
0
        const char *pszRFlag = "", *pszWFlag, *pszVirtualIO, *pszSubdatasets;
3672
0
        CSLConstList papszMD = GDALGetMetadata(hDriver, nullptr);
3673
3674
0
        if (nOptions == GDAL_OF_RASTER &&
3675
0
            !CPLFetchBool(papszMD, GDAL_DCAP_RASTER, false) &&
3676
            // HACK For CPHD driver to appear
3677
0
            !CPLFetchBool(papszMD, GDAL_DCAP_MULTIDIM_RASTER, false))
3678
0
            continue;
3679
0
        if (nOptions == GDAL_OF_VECTOR &&
3680
0
            !CPLFetchBool(papszMD, GDAL_DCAP_VECTOR, false))
3681
0
            continue;
3682
0
        if (nOptions == GDAL_OF_GNM &&
3683
0
            !CPLFetchBool(papszMD, GDAL_DCAP_GNM, false))
3684
0
            continue;
3685
0
        if (nOptions == GDAL_OF_MULTIDIM_RASTER &&
3686
0
            !CPLFetchBool(papszMD, GDAL_DCAP_MULTIDIM_RASTER, false))
3687
0
            continue;
3688
3689
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_OPEN, false))
3690
0
            pszRFlag = "r";
3691
3692
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_CREATE, false))
3693
0
            pszWFlag = "w+";
3694
0
        else if (CPLFetchBool(papszMD, GDAL_DCAP_CREATECOPY, false))
3695
0
            pszWFlag = "w";
3696
0
        else
3697
0
            pszWFlag = "o";
3698
3699
0
        const char *pszUpdate = "";
3700
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_UPDATE, false))
3701
0
            pszUpdate = "u";
3702
3703
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_VIRTUALIO, false))
3704
0
            pszVirtualIO = "v";
3705
0
        else
3706
0
            pszVirtualIO = "";
3707
3708
0
        if (CPLFetchBool(papszMD, GDAL_DMD_SUBDATASETS, false))
3709
0
            pszSubdatasets = "s";
3710
0
        else
3711
0
            pszSubdatasets = "";
3712
3713
0
        CPLString osKind;
3714
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_RASTER, false))
3715
0
            osKind = "raster";
3716
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_MULTIDIM_RASTER, false))
3717
0
        {
3718
0
            if (!osKind.empty())
3719
0
                osKind += ',';
3720
0
            osKind += "multidimensional raster";
3721
0
        }
3722
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_VECTOR, false))
3723
0
        {
3724
0
            if (!osKind.empty())
3725
0
                osKind += ',';
3726
0
            osKind += "vector";
3727
0
        }
3728
0
        if (CPLFetchBool(papszMD, GDAL_DCAP_GNM, false))
3729
0
        {
3730
0
            if (!osKind.empty())
3731
0
                osKind += ',';
3732
0
            osKind += "geography network";
3733
0
        }
3734
0
        if (osKind.empty())
3735
0
            osKind = "unknown kind";
3736
3737
0
        std::string osExtensions;
3738
0
        if (const char *pszExtensions = CSLFetchNameValueDef(
3739
0
                papszMD, GDAL_DMD_EXTENSIONS,
3740
0
                CSLFetchNameValue(papszMD, GDAL_DMD_EXTENSION)))
3741
0
        {
3742
0
            const CPLStringList aosExt(
3743
0
                CSLTokenizeString2(pszExtensions, " ", 0));
3744
0
            for (int i = 0; i < aosExt.size(); ++i)
3745
0
            {
3746
0
                if (i == 0)
3747
0
                    osExtensions = " (*.";
3748
0
                else
3749
0
                    osExtensions += ", *.";
3750
0
                osExtensions += aosExt[i];
3751
0
            }
3752
0
            if (!osExtensions.empty())
3753
0
                osExtensions += ')';
3754
0
        }
3755
3756
0
        ret += CPLSPrintf("  %s -%s- (%s%s%s%s%s): %s%s\n", /*ok*/
3757
0
                          GDALGetDriverShortName(hDriver), osKind.c_str(),
3758
0
                          pszRFlag, pszWFlag, pszUpdate, pszVirtualIO,
3759
0
                          pszSubdatasets, GDALGetDriverLongName(hDriver),
3760
0
                          osExtensions.c_str());
3761
0
    }
3762
3763
0
    return ret;
3764
0
}
3765
3766
/************************************************************************/
3767
/*                    GDALGeneralCmdLineProcessor()                     */
3768
/************************************************************************/
3769
3770
/**
3771
 * \brief General utility option processing.
3772
 *
3773
 * This function is intended to provide a variety of generic commandline
3774
 * options for all GDAL commandline utilities.  It takes care of the following
3775
 * commandline options:
3776
 *
3777
 *  \--version: report version of GDAL in use.
3778
 *  \--build: report build info about GDAL in use.
3779
 *  \--license: report GDAL license info.
3780
 *  \--formats: report all format drivers configured. Can be used with -json since 3.10
3781
 *  \--format [format]: report details of one format driver.
3782
 *  \--optfile filename: expand an option file into the argument list.
3783
 *  \--config key value: set system configuration option.
3784
 *  \--config key=value: set system configuration option (since GDAL 3.9)
3785
 *  \--debug [on/off/value]: set debug level.
3786
 *  \--mempreload dir: preload directory contents into /vsimem
3787
 *  \--pause: Pause for user input (allows time to attach debugger)
3788
 *  \--locale [locale]: Install a locale using setlocale() (debugging)
3789
 *  \--help-general: report detailed help on general options.
3790
 *
3791
 * The argument array is replaced "in place" and should be freed with
3792
 * CSLDestroy() when no longer needed.  The typical usage looks something
3793
 * like the following.  Note that the formats should be registered so that
3794
 * the \--formats and \--format options will work properly.
3795
 *
3796
 *  int main( int argc, char ** argv )
3797
 *  {
3798
 *    GDALAllRegister();
3799
 *
3800
 *    argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
3801
 *    if( argc < 1 )
3802
 *        exit( -argc );
3803
 *
3804
 * @param nArgc number of values in the argument list.
3805
 * @param ppapszArgv pointer to the argument list array (will be updated in
3806
 * place).
3807
 * @param nOptions a or-able combination of GDAL_OF_RASTER and GDAL_OF_VECTOR
3808
 *                 to determine which drivers should be displayed by \--formats.
3809
 *                 If set to 0, GDAL_OF_RASTER is assumed.
3810
 *
3811
 * @return updated nArgc argument count.  Return of 0 requests terminate
3812
 * without error, return of -1 requests exit with error code.
3813
 */
3814
3815
int CPL_STDCALL GDALGeneralCmdLineProcessor(int nArgc, char ***ppapszArgv,
3816
                                            int nOptions)
3817
3818
0
{
3819
0
    CPLStringList aosReturn;
3820
0
    int iArg;
3821
0
    char **papszArgv = *ppapszArgv;
3822
3823
    /* -------------------------------------------------------------------- */
3824
    /*      Preserve the program name.                                      */
3825
    /* -------------------------------------------------------------------- */
3826
0
    aosReturn.AddString(papszArgv[0]);
3827
3828
    /* ==================================================================== */
3829
    /*      Loop over all arguments.                                        */
3830
    /* ==================================================================== */
3831
3832
    // Start with --debug, so that "my_command --config UNKNOWN_CONFIG_OPTION --debug on"
3833
    // detects and warns about a unknown config option.
3834
0
    for (iArg = 1; iArg < nArgc; iArg++)
3835
0
    {
3836
0
        if (EQUAL(papszArgv[iArg], "--config") && iArg + 2 < nArgc &&
3837
0
            EQUAL(papszArgv[iArg + 1], "CPL_DEBUG"))
3838
0
        {
3839
0
            if (iArg + 1 >= nArgc)
3840
0
            {
3841
0
                CPLError(CE_Failure, CPLE_AppDefined,
3842
0
                         "--config option given without a key=value argument.");
3843
0
                return -1;
3844
0
            }
3845
3846
0
            const char *pszArg = papszArgv[iArg + 1];
3847
0
            if (strchr(pszArg, '=') != nullptr)
3848
0
            {
3849
0
                char *pszKey = nullptr;
3850
0
                const char *pszValue = CPLParseNameValue(pszArg, &pszKey);
3851
0
                if (pszKey && !EQUAL(pszKey, "CPL_DEBUG") && pszValue)
3852
0
                {
3853
0
                    CPLSetConfigOption(pszKey, pszValue);
3854
0
                }
3855
0
                CPLFree(pszKey);
3856
0
                ++iArg;
3857
0
            }
3858
0
            else
3859
0
            {
3860
                // cppcheck-suppress knownConditionTrueFalse
3861
0
                if (iArg + 2 >= nArgc)
3862
0
                {
3863
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3864
0
                             "--config option given without a key and value "
3865
0
                             "argument.");
3866
0
                    return -1;
3867
0
                }
3868
3869
0
                if (!EQUAL(papszArgv[iArg + 1], "CPL_DEBUG"))
3870
0
                    CPLSetConfigOption(papszArgv[iArg + 1],
3871
0
                                       papszArgv[iArg + 2]);
3872
3873
0
                iArg += 2;
3874
0
            }
3875
0
        }
3876
0
        else if (EQUAL(papszArgv[iArg], "--debug"))
3877
0
        {
3878
0
            if (iArg + 1 >= nArgc)
3879
0
            {
3880
0
                CPLError(CE_Failure, CPLE_AppDefined,
3881
0
                         "--debug option given without debug level.");
3882
0
                return -1;
3883
0
            }
3884
3885
0
            CPLSetConfigOption("CPL_DEBUG", papszArgv[iArg + 1]);
3886
0
            iArg += 1;
3887
0
        }
3888
0
    }
3889
3890
0
    for (iArg = 1; iArg < nArgc; iArg++)
3891
0
    {
3892
        /* --------------------------------------------------------------------
3893
         */
3894
        /*      --version */
3895
        /* --------------------------------------------------------------------
3896
         */
3897
0
        if (EQUAL(papszArgv[iArg], "--version"))
3898
0
        {
3899
0
            printf("%s\n", GDALVersionInfo("--version")); /*ok*/
3900
0
            return 0;
3901
0
        }
3902
3903
        /* --------------------------------------------------------------------
3904
         */
3905
        /*      --build */
3906
        /* --------------------------------------------------------------------
3907
         */
3908
0
        else if (EQUAL(papszArgv[iArg], "--build"))
3909
0
        {
3910
0
            printf("%s", GDALVersionInfo("BUILD_INFO")); /*ok*/
3911
0
            return 0;
3912
0
        }
3913
3914
        /* --------------------------------------------------------------------
3915
         */
3916
        /*      --license */
3917
        /* --------------------------------------------------------------------
3918
         */
3919
0
        else if (EQUAL(papszArgv[iArg], "--license"))
3920
0
        {
3921
0
            printf("%s\n", GDALVersionInfo("LICENSE")); /*ok*/
3922
0
            return 0;
3923
0
        }
3924
3925
        /* --------------------------------------------------------------------
3926
         */
3927
        /*      --config */
3928
        /* --------------------------------------------------------------------
3929
         */
3930
0
        else if (EQUAL(papszArgv[iArg], "--config"))
3931
0
        {
3932
0
            if (iArg + 1 >= nArgc)
3933
0
            {
3934
0
                CPLError(CE_Failure, CPLE_AppDefined,
3935
0
                         "--config option given without a key=value argument.");
3936
0
                return -1;
3937
0
            }
3938
3939
0
            const char *pszArg = papszArgv[iArg + 1];
3940
0
            if (strchr(pszArg, '=') != nullptr)
3941
0
            {
3942
0
                char *pszKey = nullptr;
3943
0
                const char *pszValue = CPLParseNameValue(pszArg, &pszKey);
3944
0
                if (pszKey && !EQUAL(pszKey, "CPL_DEBUG") && pszValue)
3945
0
                {
3946
0
                    CPLSetConfigOption(pszKey, pszValue);
3947
0
                }
3948
0
                CPLFree(pszKey);
3949
0
                ++iArg;
3950
0
            }
3951
0
            else
3952
0
            {
3953
0
                if (iArg + 2 >= nArgc)
3954
0
                {
3955
0
                    CPLError(CE_Failure, CPLE_AppDefined,
3956
0
                             "--config option given without a key and value "
3957
0
                             "argument.");
3958
0
                    return -1;
3959
0
                }
3960
3961
0
                if (!EQUAL(papszArgv[iArg + 1], "CPL_DEBUG"))
3962
0
                    CPLSetConfigOption(papszArgv[iArg + 1],
3963
0
                                       papszArgv[iArg + 2]);
3964
3965
0
                iArg += 2;
3966
0
            }
3967
0
        }
3968
3969
        /* --------------------------------------------------------------------
3970
         */
3971
        /*      --mempreload */
3972
        /* --------------------------------------------------------------------
3973
         */
3974
0
        else if (EQUAL(papszArgv[iArg], "--mempreload"))
3975
0
        {
3976
0
            if (iArg + 1 >= nArgc)
3977
0
            {
3978
0
                CPLError(CE_Failure, CPLE_AppDefined,
3979
0
                         "--mempreload option given without directory path.");
3980
0
                return -1;
3981
0
            }
3982
3983
0
            char **papszFiles = VSIReadDir(papszArgv[iArg + 1]);
3984
0
            if (CSLCount(papszFiles) == 0)
3985
0
            {
3986
0
                CPLError(CE_Failure, CPLE_AppDefined,
3987
0
                         "--mempreload given invalid or empty directory.");
3988
0
                return -1;
3989
0
            }
3990
3991
0
            for (int i = 0; papszFiles[i] != nullptr; i++)
3992
0
            {
3993
0
                if (EQUAL(papszFiles[i], ".") || EQUAL(papszFiles[i], ".."))
3994
0
                    continue;
3995
3996
0
                std::string osOldPath;
3997
0
                CPLString osNewPath;
3998
0
                osOldPath = CPLFormFilenameSafe(papszArgv[iArg + 1],
3999
0
                                                papszFiles[i], nullptr);
4000
0
                osNewPath.Printf("/vsimem/%s", papszFiles[i]);
4001
4002
0
                VSIStatBufL sStatBuf;
4003
0
                if (VSIStatL(osOldPath.c_str(), &sStatBuf) != 0 ||
4004
0
                    VSI_ISDIR(sStatBuf.st_mode))
4005
0
                {
4006
0
                    CPLDebug("VSI", "Skipping preload of %s.",
4007
0
                             osOldPath.c_str());
4008
0
                    continue;
4009
0
                }
4010
4011
0
                CPLDebug("VSI", "Preloading %s to %s.", osOldPath.c_str(),
4012
0
                         osNewPath.c_str());
4013
4014
0
                if (CPLCopyFile(osNewPath, osOldPath.c_str()) != 0)
4015
0
                {
4016
0
                    CPLError(CE_Failure, CPLE_AppDefined,
4017
0
                             "Failed to copy %s to /vsimem", osOldPath.c_str());
4018
0
                    return -1;
4019
0
                }
4020
0
            }
4021
4022
0
            CSLDestroy(papszFiles);
4023
0
            iArg += 1;
4024
0
        }
4025
4026
        /* --------------------------------------------------------------------
4027
         */
4028
        /*      --debug */
4029
        /* --------------------------------------------------------------------
4030
         */
4031
0
        else if (EQUAL(papszArgv[iArg], "--debug"))
4032
0
        {
4033
0
            if (iArg + 1 >= nArgc)
4034
0
            {
4035
0
                CPLError(CE_Failure, CPLE_AppDefined,
4036
0
                         "--debug option given without debug level.");
4037
0
                return -1;
4038
0
            }
4039
4040
0
            iArg += 1;
4041
0
        }
4042
4043
        /* --------------------------------------------------------------------
4044
         */
4045
        /*      --optfile */
4046
        /* --------------------------------------------------------------------
4047
         */
4048
0
        else if (EQUAL(papszArgv[iArg], "--optfile"))
4049
0
        {
4050
0
            if (iArg + 1 >= nArgc)
4051
0
            {
4052
0
                CPLError(CE_Failure, CPLE_AppDefined,
4053
0
                         "--optfile option given without filename.");
4054
0
                return -1;
4055
0
            }
4056
4057
0
            VSILFILE *fpOptFile = VSIFOpenL(papszArgv[iArg + 1], "rb");
4058
4059
0
            if (fpOptFile == nullptr)
4060
0
            {
4061
0
                CPLError(CE_Failure, CPLE_AppDefined,
4062
0
                         "Unable to open optfile '%s'.\n%s",
4063
0
                         papszArgv[iArg + 1], VSIStrerror(errno));
4064
0
                return -1;
4065
0
            }
4066
4067
0
            const char *pszLine;
4068
0
            CPLStringList aosArgvOptfile;
4069
            // dummy value as first argument to please
4070
            // GDALGeneralCmdLineProcessor()
4071
0
            aosArgvOptfile.AddString("");
4072
0
            bool bHasOptfile = false;
4073
0
            while ((pszLine = CPLReadLineL(fpOptFile)) != nullptr)
4074
0
            {
4075
0
                if (pszLine[0] == '#' || strlen(pszLine) == 0)
4076
0
                    continue;
4077
4078
0
                char **papszTokens = CSLTokenizeString(pszLine);
4079
0
                for (int i = 0;
4080
0
                     papszTokens != nullptr && papszTokens[i] != nullptr; i++)
4081
0
                {
4082
0
                    if (EQUAL(papszTokens[i], "--optfile"))
4083
0
                    {
4084
                        // To avoid potential recursion
4085
0
                        CPLError(CE_Warning, CPLE_AppDefined,
4086
0
                                 "--optfile not supported in a option file");
4087
0
                        bHasOptfile = true;
4088
0
                    }
4089
0
                    aosArgvOptfile.AddStringDirectly(papszTokens[i]);
4090
0
                    papszTokens[i] = nullptr;
4091
0
                }
4092
0
                CSLDestroy(papszTokens);
4093
0
            }
4094
4095
0
            VSIFCloseL(fpOptFile);
4096
4097
0
            char **papszArgvOptfile = aosArgvOptfile.StealList();
4098
0
            if (!bHasOptfile)
4099
0
            {
4100
0
                char **papszArgvOptfileBefore = papszArgvOptfile;
4101
0
                if (GDALGeneralCmdLineProcessor(CSLCount(papszArgvOptfile),
4102
0
                                                &papszArgvOptfile,
4103
0
                                                nOptions) < 0)
4104
0
                {
4105
0
                    CSLDestroy(papszArgvOptfile);
4106
0
                    return -1;
4107
0
                }
4108
0
                CSLDestroy(papszArgvOptfileBefore);
4109
0
            }
4110
4111
0
            char **papszIter = papszArgvOptfile + 1;
4112
0
            while (*papszIter)
4113
0
            {
4114
0
                aosReturn.AddString(*papszIter);
4115
0
                ++papszIter;
4116
0
            }
4117
0
            CSLDestroy(papszArgvOptfile);
4118
4119
0
            iArg += 1;
4120
0
        }
4121
4122
        /* --------------------------------------------------------------------
4123
         */
4124
        /*      --formats */
4125
        /* --------------------------------------------------------------------
4126
         */
4127
0
        else if (EQUAL(papszArgv[iArg], "--formats"))
4128
0
        {
4129
0
            bool bJSON = false;
4130
0
            for (int i = 1; i < nArgc; i++)
4131
0
            {
4132
0
                if (strcmp(papszArgv[i], "-json") == 0 ||
4133
0
                    strcmp(papszArgv[i], "--json") == 0)
4134
0
                {
4135
0
                    bJSON = true;
4136
0
                    break;
4137
0
                }
4138
0
            }
4139
4140
0
            printf("%s", GDALPrintDriverList(nOptions, bJSON).c_str()); /*ok*/
4141
4142
0
            return 0;
4143
0
        }
4144
4145
        /* --------------------------------------------------------------------
4146
         */
4147
        /*      --format */
4148
        /* --------------------------------------------------------------------
4149
         */
4150
0
        else if (EQUAL(papszArgv[iArg], "--format"))
4151
0
        {
4152
0
            GDALDriverH hDriver;
4153
4154
0
            if (iArg + 1 >= nArgc)
4155
0
            {
4156
0
                CPLError(CE_Failure, CPLE_AppDefined,
4157
0
                         "--format option given without a format code.");
4158
0
                return -1;
4159
0
            }
4160
4161
0
            hDriver = GDALGetDriverByName(papszArgv[iArg + 1]);
4162
0
            if (hDriver == nullptr)
4163
0
            {
4164
0
                CPLError(CE_Failure, CPLE_AppDefined,
4165
0
                         "--format option given with format '%s', but that "
4166
0
                         "format not\nrecognised.  Use the --formats option "
4167
0
                         "to get a list of available formats,\n"
4168
0
                         "and use the short code (i.e. GTiff or HFA) as the "
4169
0
                         "format identifier.\n",
4170
0
                         papszArgv[iArg + 1]);
4171
0
                return -1;
4172
0
            }
4173
4174
0
            printf("Format Details:\n"); /*ok*/
4175
0
            printf(/*ok*/ "  Short Name: %s\n",
4176
0
                   GDALGetDriverShortName(hDriver));
4177
0
            printf(/*ok*/ "  Long Name: %s\n", GDALGetDriverLongName(hDriver));
4178
4179
0
            CSLConstList papszMD = GDALGetMetadata(hDriver, nullptr);
4180
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_RASTER, false))
4181
0
                printf("  Supports: Raster\n"); /*ok*/
4182
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_MULTIDIM_RASTER, false))
4183
0
                printf("  Supports: Multidimensional raster\n"); /*ok*/
4184
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_VECTOR, false))
4185
0
                printf("  Supports: Vector\n"); /*ok*/
4186
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_GNM, false))
4187
0
                printf("  Supports: Geography Network\n"); /*ok*/
4188
4189
0
            const char *pszExt =
4190
0
                CSLFetchNameValue(papszMD, GDAL_DMD_EXTENSIONS);
4191
0
            if (pszExt != nullptr)
4192
0
                printf("  Extension%s: %s\n", /*ok*/
4193
0
                       (strchr(pszExt, ' ') ? "s" : ""), pszExt);
4194
4195
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_MIMETYPE))
4196
0
                printf("  Mime Type: %s\n", /*ok*/
4197
0
                       CSLFetchNameValue(papszMD, GDAL_DMD_MIMETYPE));
4198
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_HELPTOPIC))
4199
0
                printf("  Help Topic: %s\n", /*ok*/
4200
0
                       CSLFetchNameValue(papszMD, GDAL_DMD_HELPTOPIC));
4201
4202
0
            if (CPLFetchBool(papszMD, GDAL_DMD_SUBDATASETS, false))
4203
0
                printf("  Supports: Raster subdatasets\n"); /*ok*/
4204
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_OPEN, false))
4205
0
                printf("  Supports: Open() - Open existing dataset.\n"); /*ok*/
4206
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_CREATE, false))
4207
0
                printf(/*ok*/
4208
0
                       "  Supports: Create() - Create writable dataset.\n");
4209
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_CREATE_MULTIDIMENSIONAL, false))
4210
0
                printf(/*ok*/ "  Supports: CreateMultiDimensional() - Create "
4211
0
                              "multidimensional dataset.\n");
4212
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_CREATECOPY, false))
4213
0
                printf(/*ok*/ "  Supports: CreateCopy() - Create dataset by "
4214
0
                              "copying "
4215
0
                              "another.\n");
4216
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_UPDATE, false))
4217
0
                printf("  Supports: Update\n"); /*ok*/
4218
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_VIRTUALIO, false))
4219
0
                printf("  Supports: Virtual IO - eg. /vsimem/\n"); /*ok*/
4220
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_CREATIONDATATYPES))
4221
0
                printf("  Creation Datatypes: %s\n", /*ok*/
4222
0
                       CSLFetchNameValue(papszMD, GDAL_DMD_CREATIONDATATYPES));
4223
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_CREATIONFIELDDATATYPES))
4224
0
                printf("  Creation Field Datatypes: %s\n", /*ok*/
4225
0
                       CSLFetchNameValue(papszMD,
4226
0
                                         GDAL_DMD_CREATIONFIELDDATATYPES));
4227
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_CREATIONFIELDDATASUBTYPES))
4228
0
                printf("  Creation Field Data Sub-types: %s\n", /*ok*/
4229
0
                       CSLFetchNameValue(papszMD,
4230
0
                                         GDAL_DMD_CREATIONFIELDDATASUBTYPES));
4231
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_NOTNULL_FIELDS, false))
4232
0
                printf(/*ok*/ "  Supports: Creating fields with NOT NULL "
4233
0
                              "constraint.\n");
4234
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_UNIQUE_FIELDS, false))
4235
0
                printf(/*ok*/
4236
0
                       "  Supports: Creating fields with UNIQUE constraint.\n");
4237
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_DEFAULT_FIELDS, false))
4238
0
                printf(/*ok*/
4239
0
                       "  Supports: Creating fields with DEFAULT values.\n");
4240
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_NOTNULL_GEOMFIELDS, false))
4241
0
                /*ok*/ printf(
4242
0
                    "  Supports: Creating geometry fields with NOT NULL "
4243
0
                    "constraint.\n");
4244
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_CURVE_GEOMETRIES, false))
4245
0
                /*ok*/ printf("  Supports: Curve geometries.\n");
4246
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_Z_GEOMETRIES, false))
4247
0
                /*ok*/ printf("  Supports: 3D (Z) geometries.\n");
4248
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_MEASURED_GEOMETRIES, false))
4249
0
                /*ok*/ printf("  Supports: Measured (M) geometries.\n");
4250
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION,
4251
0
                             false))
4252
0
                /*ok*/ printf("  Supports: Writing geometries with given "
4253
0
                              "coordinate precision\n");
4254
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_FEATURE_STYLES_READ, false))
4255
0
                printf("  Supports: Reading feature styles.\n"); /*ok*/
4256
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_FEATURE_STYLES_WRITE, false))
4257
0
                printf("  Supports: Writing feature styles.\n"); /*ok*/
4258
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_COORDINATE_EPOCH, false))
4259
0
                printf("  Supports: Coordinate epoch.\n"); /*ok*/
4260
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, false))
4261
0
                printf("  Supports: Multiple vector layers.\n"); /*ok*/
4262
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_FIELD_DOMAINS, false))
4263
0
                printf("  Supports: Reading field domains.\n"); /*ok*/
4264
0
            if (CPLFetchBool(papszMD, GDAL_DCAP_UPSERT, false))
4265
0
                printf("  Supports: Feature upsert.\n"); /*ok*/
4266
0
            if (CSLFetchNameValue(papszMD,
4267
0
                                  GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES))
4268
0
                printf("  Creation field domain types: %s\n", /*ok*/
4269
0
                       CSLFetchNameValue(papszMD,
4270
0
                                         GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES));
4271
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_SUPPORTED_SQL_DIALECTS))
4272
0
                printf("  Supported SQL dialects: %s\n", /*ok*/
4273
0
                       CSLFetchNameValue(papszMD,
4274
0
                                         GDAL_DMD_SUPPORTED_SQL_DIALECTS));
4275
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_UPDATE_ITEMS))
4276
0
                printf("  Supported items for update: %s\n", /*ok*/
4277
0
                       CSLFetchNameValue(papszMD, GDAL_DMD_UPDATE_ITEMS));
4278
4279
0
            for (const char *key :
4280
0
                 {GDAL_DMD_CREATIONOPTIONLIST,
4281
0
                  GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST,
4282
0
                  GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
4283
0
                  GDAL_DMD_MULTIDIM_GROUP_CREATIONOPTIONLIST,
4284
0
                  GDAL_DMD_MULTIDIM_DIMENSION_CREATIONOPTIONLIST,
4285
0
                  GDAL_DMD_MULTIDIM_ARRAY_CREATIONOPTIONLIST,
4286
0
                  GDAL_DMD_MULTIDIM_ARRAY_OPENOPTIONLIST,
4287
0
                  GDAL_DMD_MULTIDIM_ATTRIBUTE_CREATIONOPTIONLIST,
4288
0
                  GDAL_DS_LAYER_CREATIONOPTIONLIST})
4289
0
            {
4290
0
                if (CSLFetchNameValue(papszMD, key))
4291
0
                {
4292
0
                    CPLXMLNode *psCOL =
4293
0
                        CPLParseXMLString(CSLFetchNameValue(papszMD, key));
4294
0
                    StripIrrelevantOptions(psCOL, nOptions);
4295
0
                    char *pszFormattedXML = CPLSerializeXMLTree(psCOL);
4296
4297
0
                    CPLDestroyXMLNode(psCOL);
4298
4299
0
                    printf("\n%s\n", pszFormattedXML); /*ok*/
4300
0
                    CPLFree(pszFormattedXML);
4301
0
                }
4302
0
            }
4303
4304
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_CONNECTION_PREFIX))
4305
0
                printf("  Connection prefix: %s\n", /*ok*/
4306
0
                       CSLFetchNameValue(papszMD, GDAL_DMD_CONNECTION_PREFIX));
4307
4308
0
            if (CSLFetchNameValue(papszMD, GDAL_DMD_OPENOPTIONLIST))
4309
0
            {
4310
0
                CPLXMLNode *psCOL = CPLParseXMLString(
4311
0
                    CSLFetchNameValue(papszMD, GDAL_DMD_OPENOPTIONLIST));
4312
0
                StripIrrelevantOptions(psCOL, nOptions);
4313
0
                char *pszFormattedXML = CPLSerializeXMLTree(psCOL);
4314
4315
0
                CPLDestroyXMLNode(psCOL);
4316
4317
0
                printf("%s\n", pszFormattedXML); /*ok*/
4318
0
                CPLFree(pszFormattedXML);
4319
0
            }
4320
4321
0
            bool bFirstOtherOption = true;
4322
0
            for (CSLConstList papszIter = papszMD; papszIter && *papszIter;
4323
0
                 ++papszIter)
4324
0
            {
4325
0
                if (!STARTS_WITH(*papszIter, "DCAP_") &&
4326
0
                    !STARTS_WITH(*papszIter, "DMD_") &&
4327
0
                    !STARTS_WITH(*papszIter, "DS_") &&
4328
0
                    !STARTS_WITH(*papszIter, "OGR_DRIVER="))
4329
0
                {
4330
0
                    if (bFirstOtherOption)
4331
0
                        printf("  Other metadata items:\n"); /*ok*/
4332
0
                    bFirstOtherOption = false;
4333
0
                    printf("    %s\n", *papszIter); /*ok*/
4334
0
                }
4335
0
            }
4336
4337
0
            return 0;
4338
0
        }
4339
4340
        /* --------------------------------------------------------------------
4341
         */
4342
        /*      --help-general */
4343
        /* --------------------------------------------------------------------
4344
         */
4345
0
        else if (EQUAL(papszArgv[iArg], "--help-general"))
4346
0
        {
4347
0
            printf("Generic GDAL utility command options:\n");       /*ok*/
4348
0
            printf("  --version: report version of GDAL in use.\n"); /*ok*/
4349
0
            /*ok*/ printf(
4350
0
                "  --build: report detailed information about GDAL in "
4351
0
                "use.\n");
4352
0
            printf("  --license: report GDAL license info.\n"); /*ok*/
4353
0
            printf(                                             /*ok*/
4354
0
                   "  --formats: report all configured format drivers.\n"); /*ok*/
4355
0
            printf("  --format [<format>]: details of one format.\n"); /*ok*/
4356
0
            /*ok*/ printf(
4357
0
                "  --optfile filename: expand an option file into the "
4358
0
                "argument list.\n");
4359
0
            printf(/*ok*/
4360
0
                   "  --config <key> <value> or --config <key>=<value>: set "
4361
0
                   "system configuration option.\n");               /*ok*/
4362
0
            printf("  --debug [on/off/value]: set debug level.\n"); /*ok*/
4363
0
            /*ok*/ printf(                                          /*ok*/
4364
0
                          "  --pause: wait for user input, time to attach "
4365
0
                          "debugger\n");
4366
0
            printf("  --locale [<locale>]: install locale for debugging " /*ok*/
4367
0
                   "(i.e. en_US.UTF-8)\n");
4368
0
            printf("  --help-general: report detailed help on general " /*ok*/
4369
0
                   "options.\n");
4370
4371
0
            return 0;
4372
0
        }
4373
4374
        /* --------------------------------------------------------------------
4375
         */
4376
        /*      --locale */
4377
        /* --------------------------------------------------------------------
4378
         */
4379
0
        else if (iArg < nArgc - 1 && EQUAL(papszArgv[iArg], "--locale"))
4380
0
        {
4381
0
            CPLsetlocale(LC_ALL, papszArgv[++iArg]);
4382
0
        }
4383
4384
        /* --------------------------------------------------------------------
4385
         */
4386
        /*      --pause */
4387
        /* --------------------------------------------------------------------
4388
         */
4389
0
        else if (EQUAL(papszArgv[iArg], "--pause"))
4390
0
        {
4391
0
            std::cout << "Hit <ENTER> to Continue." << std::endl;
4392
0
            std::cin.clear();
4393
0
            std::cin.ignore(cpl::NumericLimits<std::streamsize>::max(), '\n');
4394
0
        }
4395
4396
        /* --------------------------------------------------------------------
4397
         */
4398
        /*      Carry through unrecognized options. */
4399
        /* --------------------------------------------------------------------
4400
         */
4401
0
        else
4402
0
        {
4403
0
            aosReturn.AddString(papszArgv[iArg]);
4404
0
        }
4405
0
    }
4406
4407
0
    const int nSize = aosReturn.size();
4408
0
    *ppapszArgv = aosReturn.StealList();
4409
4410
0
    return nSize;
4411
0
}
4412
4413
/************************************************************************/
4414
/*                          _FetchDblFromMD()                           */
4415
/************************************************************************/
4416
4417
static bool _FetchDblFromMD(CSLConstList papszMD, const char *pszKey,
4418
                            double *padfTarget, int nCount, double dfDefault)
4419
4420
0
{
4421
0
    char szFullKey[200];
4422
4423
0
    snprintf(szFullKey, sizeof(szFullKey), "%s", pszKey);
4424
4425
0
    const char *pszValue = CSLFetchNameValue(papszMD, szFullKey);
4426
4427
0
    for (int i = 0; i < nCount; i++)
4428
0
        padfTarget[i] = dfDefault;
4429
4430
0
    if (pszValue == nullptr)
4431
0
        return false;
4432
4433
0
    if (nCount == 1)
4434
0
    {
4435
0
        *padfTarget = CPLAtofM(pszValue);
4436
0
        return true;
4437
0
    }
4438
4439
0
    char **papszTokens = CSLTokenizeStringComplex(pszValue, " ,", FALSE, FALSE);
4440
4441
0
    if (CSLCount(papszTokens) != nCount)
4442
0
    {
4443
0
        CSLDestroy(papszTokens);
4444
0
        return false;
4445
0
    }
4446
4447
0
    for (int i = 0; i < nCount; i++)
4448
0
        padfTarget[i] = CPLAtofM(papszTokens[i]);
4449
4450
0
    CSLDestroy(papszTokens);
4451
4452
0
    return true;
4453
0
}
4454
4455
/************************************************************************/
4456
/*                         GDALExtractRPCInfo()                         */
4457
/************************************************************************/
4458
4459
/** Extract RPC info from metadata, and apply to an RPCInfo structure.
4460
 *
4461
 * The inverse of this function is RPCInfoV1ToMD() in alg/gdal_rpc.cpp
4462
 *
4463
 * @param papszMD Dictionary of metadata representing RPC
4464
 * @param psRPC (output) Pointer to structure to hold the RPC values.
4465
 * @return TRUE in case of success. FALSE in case of failure.
4466
 */
4467
int CPL_STDCALL GDALExtractRPCInfoV1(CSLConstList papszMD, GDALRPCInfoV1 *psRPC)
4468
4469
0
{
4470
0
    GDALRPCInfoV2 sRPC;
4471
0
    if (!GDALExtractRPCInfoV2(papszMD, &sRPC))
4472
0
        return FALSE;
4473
0
    memcpy(psRPC, &sRPC, sizeof(GDALRPCInfoV1));
4474
0
    return TRUE;
4475
0
}
4476
4477
/** Extract RPC info from metadata, and apply to an RPCInfo structure.
4478
 *
4479
 * The inverse of this function is RPCInfoV2ToMD() in alg/gdal_rpc.cpp
4480
 *
4481
 * @param papszMD Dictionary of metadata representing RPC
4482
 * @param psRPC (output) Pointer to structure to hold the RPC values.
4483
 * @return TRUE in case of success. FALSE in case of failure.
4484
 */
4485
int CPL_STDCALL GDALExtractRPCInfoV2(CSLConstList papszMD, GDALRPCInfoV2 *psRPC)
4486
4487
0
{
4488
0
    if (CSLFetchNameValue(papszMD, RPC_LINE_NUM_COEFF) == nullptr)
4489
0
        return FALSE;
4490
4491
0
    if (CSLFetchNameValue(papszMD, RPC_LINE_NUM_COEFF) == nullptr ||
4492
0
        CSLFetchNameValue(papszMD, RPC_LINE_DEN_COEFF) == nullptr ||
4493
0
        CSLFetchNameValue(papszMD, RPC_SAMP_NUM_COEFF) == nullptr ||
4494
0
        CSLFetchNameValue(papszMD, RPC_SAMP_DEN_COEFF) == nullptr)
4495
0
    {
4496
0
        CPLError(CE_Failure, CPLE_AppDefined,
4497
0
                 "Some required RPC metadata missing in GDALExtractRPCInfo()");
4498
0
        return FALSE;
4499
0
    }
4500
4501
0
    _FetchDblFromMD(papszMD, RPC_ERR_BIAS, &(psRPC->dfERR_BIAS), 1, -1.0);
4502
0
    _FetchDblFromMD(papszMD, RPC_ERR_RAND, &(psRPC->dfERR_RAND), 1, -1.0);
4503
0
    _FetchDblFromMD(papszMD, RPC_LINE_OFF, &(psRPC->dfLINE_OFF), 1, 0.0);
4504
0
    _FetchDblFromMD(papszMD, RPC_LINE_SCALE, &(psRPC->dfLINE_SCALE), 1, 1.0);
4505
0
    _FetchDblFromMD(papszMD, RPC_SAMP_OFF, &(psRPC->dfSAMP_OFF), 1, 0.0);
4506
0
    _FetchDblFromMD(papszMD, RPC_SAMP_SCALE, &(psRPC->dfSAMP_SCALE), 1, 1.0);
4507
0
    _FetchDblFromMD(papszMD, RPC_HEIGHT_OFF, &(psRPC->dfHEIGHT_OFF), 1, 0.0);
4508
0
    _FetchDblFromMD(papszMD, RPC_HEIGHT_SCALE, &(psRPC->dfHEIGHT_SCALE), 1,
4509
0
                    1.0);
4510
0
    _FetchDblFromMD(papszMD, RPC_LAT_OFF, &(psRPC->dfLAT_OFF), 1, 0.0);
4511
0
    _FetchDblFromMD(papszMD, RPC_LAT_SCALE, &(psRPC->dfLAT_SCALE), 1, 1.0);
4512
0
    _FetchDblFromMD(papszMD, RPC_LONG_OFF, &(psRPC->dfLONG_OFF), 1, 0.0);
4513
0
    _FetchDblFromMD(papszMD, RPC_LONG_SCALE, &(psRPC->dfLONG_SCALE), 1, 1.0);
4514
4515
0
    _FetchDblFromMD(papszMD, RPC_LINE_NUM_COEFF, psRPC->adfLINE_NUM_COEFF, 20,
4516
0
                    0.0);
4517
0
    _FetchDblFromMD(papszMD, RPC_LINE_DEN_COEFF, psRPC->adfLINE_DEN_COEFF, 20,
4518
0
                    0.0);
4519
0
    _FetchDblFromMD(papszMD, RPC_SAMP_NUM_COEFF, psRPC->adfSAMP_NUM_COEFF, 20,
4520
0
                    0.0);
4521
0
    _FetchDblFromMD(papszMD, RPC_SAMP_DEN_COEFF, psRPC->adfSAMP_DEN_COEFF, 20,
4522
0
                    0.0);
4523
4524
0
    _FetchDblFromMD(papszMD, RPC_MIN_LONG, &(psRPC->dfMIN_LONG), 1, -180.0);
4525
0
    _FetchDblFromMD(papszMD, RPC_MIN_LAT, &(psRPC->dfMIN_LAT), 1, -90.0);
4526
0
    _FetchDblFromMD(papszMD, RPC_MAX_LONG, &(psRPC->dfMAX_LONG), 1, 180.0);
4527
0
    _FetchDblFromMD(papszMD, RPC_MAX_LAT, &(psRPC->dfMAX_LAT), 1, 90.0);
4528
4529
0
    return TRUE;
4530
0
}
4531
4532
/************************************************************************/
4533
/*                     GDALFindAssociatedAuxFile()                      */
4534
/************************************************************************/
4535
4536
GDALDataset *GDALFindAssociatedAuxFile(const char *pszBasename,
4537
                                       GDALAccess eAccess,
4538
                                       GDALDataset *poDependentDS)
4539
4540
399k
{
4541
399k
    const char *pszAuxSuffixLC = "aux";
4542
399k
    const char *pszAuxSuffixUC = "AUX";
4543
4544
399k
    if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), pszAuxSuffixLC))
4545
61.4k
        return nullptr;
4546
4547
    /* -------------------------------------------------------------------- */
4548
    /*      Don't even try to look for an .aux file if we don't have a      */
4549
    /*      path of any kind.                                               */
4550
    /* -------------------------------------------------------------------- */
4551
338k
    if (strlen(pszBasename) == 0)
4552
0
        return nullptr;
4553
4554
    /* -------------------------------------------------------------------- */
4555
    /*      We didn't find that, so try and find a corresponding aux        */
4556
    /*      file.  Check that we are the dependent file of the aux          */
4557
    /*      file, or if we aren't verify that the dependent file does       */
4558
    /*      not exist, likely mean it is us but some sort of renaming       */
4559
    /*      has occurred.                                                   */
4560
    /* -------------------------------------------------------------------- */
4561
338k
    CPLString osJustFile = CPLGetFilename(pszBasename);  // without dir
4562
338k
    CPLString osAuxFilename =
4563
338k
        CPLResetExtensionSafe(pszBasename, pszAuxSuffixLC);
4564
338k
    GDALDataset *poODS = nullptr;
4565
338k
    GByte abyHeader[32];
4566
4567
338k
    VSILFILE *fp = VSIFOpenL(osAuxFilename, "rb");
4568
4569
338k
    if (fp == nullptr && VSIIsCaseSensitiveFS(osAuxFilename))
4570
258k
    {
4571
        // Can't found file with lower case suffix. Try the upper case one.
4572
258k
        osAuxFilename = CPLResetExtensionSafe(pszBasename, pszAuxSuffixUC);
4573
258k
        fp = VSIFOpenL(osAuxFilename, "rb");
4574
258k
    }
4575
4576
338k
    if (fp != nullptr)
4577
81.4k
    {
4578
81.4k
        if (VSIFReadL(abyHeader, 1, 32, fp) == 32 &&
4579
81.1k
            STARTS_WITH_CI(reinterpret_cast<const char *>(abyHeader),
4580
81.4k
                           "EHFA_HEADER_TAG"))
4581
77.6k
        {
4582
            /* Avoid causing failure in opening of main file from SWIG bindings
4583
             */
4584
            /* when auxiliary file cannot be opened (#3269) */
4585
77.6k
            CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
4586
77.6k
            if (poDependentDS != nullptr && poDependentDS->GetShared())
4587
0
                poODS = GDALDataset::FromHandle(
4588
0
                    GDALOpenShared(osAuxFilename, eAccess));
4589
77.6k
            else
4590
77.6k
                poODS =
4591
77.6k
                    GDALDataset::FromHandle(GDALOpen(osAuxFilename, eAccess));
4592
77.6k
        }
4593
81.4k
        CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
4594
81.4k
    }
4595
4596
    /* -------------------------------------------------------------------- */
4597
    /*      Try replacing extension with .aux                               */
4598
    /* -------------------------------------------------------------------- */
4599
338k
    if (poODS != nullptr)
4600
68.3k
    {
4601
68.3k
        const char *pszDep =
4602
68.3k
            poODS->GetMetadataItem("HFA_DEPENDENT_FILE", "HFA");
4603
68.3k
        if (pszDep == nullptr)
4604
68.3k
        {
4605
68.3k
            CPLDebug("AUX", "Found %s but it has no dependent file, ignoring.",
4606
68.3k
                     osAuxFilename.c_str());
4607
68.3k
            GDALClose(poODS);
4608
68.3k
            poODS = nullptr;
4609
68.3k
        }
4610
0
        else if (!EQUAL(pszDep, osJustFile))
4611
0
        {
4612
0
            VSIStatBufL sStatBuf;
4613
4614
0
            if (VSIStatExL(pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
4615
0
            {
4616
0
                CPLDebug("AUX", "%s is for file %s, not %s, ignoring.",
4617
0
                         osAuxFilename.c_str(), pszDep, osJustFile.c_str());
4618
0
                GDALClose(poODS);
4619
0
                poODS = nullptr;
4620
0
            }
4621
0
            else
4622
0
            {
4623
0
                CPLDebug("AUX",
4624
0
                         "%s is for file %s, not %s, but since\n"
4625
0
                         "%s does not exist, we will use .aux file as our own.",
4626
0
                         osAuxFilename.c_str(), pszDep, osJustFile.c_str(),
4627
0
                         pszDep);
4628
0
            }
4629
0
        }
4630
4631
        /* --------------------------------------------------------------------
4632
         */
4633
        /*      Confirm that the aux file matches the configuration of the */
4634
        /*      dependent dataset. */
4635
        /* --------------------------------------------------------------------
4636
         */
4637
68.3k
        if (poODS != nullptr && poDependentDS != nullptr &&
4638
0
            (poODS->GetRasterCount() != poDependentDS->GetRasterCount() ||
4639
0
             poODS->GetRasterXSize() != poDependentDS->GetRasterXSize() ||
4640
0
             poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()))
4641
0
        {
4642
0
            CPLDebug("AUX",
4643
0
                     "Ignoring aux file %s as its raster configuration\n"
4644
0
                     "(%dP x %dL x %dB) does not match master file (%dP x %dL "
4645
0
                     "x %dB)",
4646
0
                     osAuxFilename.c_str(), poODS->GetRasterXSize(),
4647
0
                     poODS->GetRasterYSize(), poODS->GetRasterCount(),
4648
0
                     poDependentDS->GetRasterXSize(),
4649
0
                     poDependentDS->GetRasterYSize(),
4650
0
                     poDependentDS->GetRasterCount());
4651
4652
0
            GDALClose(poODS);
4653
0
            poODS = nullptr;
4654
0
        }
4655
68.3k
    }
4656
4657
    /* -------------------------------------------------------------------- */
4658
    /*      Try appending .aux to the end of the filename.                  */
4659
    /* -------------------------------------------------------------------- */
4660
338k
    if (poODS == nullptr)
4661
338k
    {
4662
338k
        osAuxFilename = pszBasename;
4663
338k
        osAuxFilename += ".";
4664
338k
        osAuxFilename += pszAuxSuffixLC;
4665
338k
        fp = VSIFOpenL(osAuxFilename, "rb");
4666
338k
        if (fp == nullptr && VSIIsCaseSensitiveFS(osAuxFilename))
4667
268k
        {
4668
            // Can't found file with lower case suffix. Try the upper case one.
4669
268k
            osAuxFilename = pszBasename;
4670
268k
            osAuxFilename += ".";
4671
268k
            osAuxFilename += pszAuxSuffixUC;
4672
268k
            fp = VSIFOpenL(osAuxFilename, "rb");
4673
268k
        }
4674
4675
338k
        if (fp != nullptr)
4676
71.1k
        {
4677
71.1k
            if (VSIFReadL(abyHeader, 1, 32, fp) == 32 &&
4678
70.7k
                STARTS_WITH_CI(reinterpret_cast<const char *>(abyHeader),
4679
71.1k
                               "EHFA_HEADER_TAG"))
4680
66.9k
            {
4681
                /* Avoid causing failure in opening of main file from SWIG
4682
                 * bindings */
4683
                /* when auxiliary file cannot be opened (#3269) */
4684
66.9k
                CPLTurnFailureIntoWarningBackuper oErrorsToWarnings{};
4685
66.9k
                if (poDependentDS != nullptr && poDependentDS->GetShared())
4686
0
                    poODS = GDALDataset::FromHandle(
4687
0
                        GDALOpenShared(osAuxFilename, eAccess));
4688
66.9k
                else
4689
66.9k
                    poODS = GDALDataset::FromHandle(
4690
66.9k
                        GDALOpen(osAuxFilename, eAccess));
4691
66.9k
            }
4692
71.1k
            CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
4693
71.1k
        }
4694
4695
338k
        if (poODS != nullptr)
4696
54.2k
        {
4697
54.2k
            const char *pszDep =
4698
54.2k
                poODS->GetMetadataItem("HFA_DEPENDENT_FILE", "HFA");
4699
54.2k
            if (pszDep == nullptr)
4700
54.2k
            {
4701
54.2k
                CPLDebug("AUX",
4702
54.2k
                         "Found %s but it has no dependent file, ignoring.",
4703
54.2k
                         osAuxFilename.c_str());
4704
54.2k
                GDALClose(poODS);
4705
54.2k
                poODS = nullptr;
4706
54.2k
            }
4707
0
            else if (!EQUAL(pszDep, osJustFile))
4708
0
            {
4709
0
                VSIStatBufL sStatBuf;
4710
4711
0
                if (VSIStatExL(pszDep, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
4712
0
                {
4713
0
                    CPLDebug("AUX", "%s is for file %s, not %s, ignoring.",
4714
0
                             osAuxFilename.c_str(), pszDep, osJustFile.c_str());
4715
0
                    GDALClose(poODS);
4716
0
                    poODS = nullptr;
4717
0
                }
4718
0
                else
4719
0
                {
4720
0
                    CPLDebug(
4721
0
                        "AUX",
4722
0
                        "%s is for file %s, not %s, but since\n"
4723
0
                        "%s does not exist, we will use .aux file as our own.",
4724
0
                        osAuxFilename.c_str(), pszDep, osJustFile.c_str(),
4725
0
                        pszDep);
4726
0
                }
4727
0
            }
4728
54.2k
        }
4729
338k
    }
4730
4731
    /* -------------------------------------------------------------------- */
4732
    /*      Confirm that the aux file matches the configuration of the      */
4733
    /*      dependent dataset.                                              */
4734
    /* -------------------------------------------------------------------- */
4735
338k
    if (poODS != nullptr && poDependentDS != nullptr &&
4736
0
        (poODS->GetRasterCount() != poDependentDS->GetRasterCount() ||
4737
0
         poODS->GetRasterXSize() != poDependentDS->GetRasterXSize() ||
4738
0
         poODS->GetRasterYSize() != poDependentDS->GetRasterYSize()))
4739
0
    {
4740
0
        CPLDebug(
4741
0
            "AUX",
4742
0
            "Ignoring aux file %s as its raster configuration\n"
4743
0
            "(%dP x %dL x %dB) does not match master file (%dP x %dL x %dB)",
4744
0
            osAuxFilename.c_str(), poODS->GetRasterXSize(),
4745
0
            poODS->GetRasterYSize(), poODS->GetRasterCount(),
4746
0
            poDependentDS->GetRasterXSize(), poDependentDS->GetRasterYSize(),
4747
0
            poDependentDS->GetRasterCount());
4748
4749
0
        GDALClose(poODS);
4750
0
        poODS = nullptr;
4751
0
    }
4752
4753
338k
    return poODS;
4754
338k
}
4755
4756
/************************************************************************/
4757
/*    Infrastructure to check that dataset characteristics are valid    */
4758
/************************************************************************/
4759
4760
CPL_C_START
4761
4762
/**
4763
 * \brief Return TRUE if the dataset dimensions are valid.
4764
 *
4765
 * @param nXSize raster width
4766
 * @param nYSize raster height
4767
 *
4768
 */
4769
int GDALCheckDatasetDimensions(int nXSize, int nYSize)
4770
353k
{
4771
353k
    if (nXSize <= 0 || nYSize <= 0)
4772
9.77k
    {
4773
9.77k
        CPLError(CE_Failure, CPLE_AppDefined,
4774
9.77k
                 "Invalid dataset dimensions : %d x %d", nXSize, nYSize);
4775
9.77k
        return FALSE;
4776
9.77k
    }
4777
343k
    return TRUE;
4778
353k
}
4779
4780
/**
4781
 * \brief Return TRUE if the band count is valid.
4782
 *
4783
 * If the configuration option GDAL_MAX_BAND_COUNT is defined,
4784
 * the band count will be compared to the maximum number of band allowed.
4785
 * If not defined, the maximum number allowed is 65536.
4786
 *
4787
 * @param nBands the band count
4788
 * @param bIsZeroAllowed TRUE if band count == 0 is allowed
4789
 *
4790
 */
4791
4792
int GDALCheckBandCount(int nBands, int bIsZeroAllowed)
4793
326k
{
4794
326k
    if (nBands < 0 || (!bIsZeroAllowed && nBands == 0))
4795
522
    {
4796
522
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid band count : %d",
4797
522
                 nBands);
4798
522
        return FALSE;
4799
522
    }
4800
326k
    const char *pszMaxBandCount =
4801
326k
        CPLGetConfigOption("GDAL_MAX_BAND_COUNT", "65536");
4802
326k
    int nMaxBands = std::clamp(atoi(pszMaxBandCount), 0, INT_MAX - 1);
4803
326k
    if (nBands > nMaxBands)
4804
223
    {
4805
223
        CPLError(CE_Failure, CPLE_AppDefined,
4806
223
                 "Invalid band count : %d. Maximum allowed currently is %d. "
4807
223
                 "Define GDAL_MAX_BAND_COUNT to a higher level if it is a "
4808
223
                 "legitimate number.",
4809
223
                 nBands, nMaxBands);
4810
223
        return FALSE;
4811
223
    }
4812
325k
    return TRUE;
4813
326k
}
4814
4815
CPL_C_END
4816
4817
/************************************************************************/
4818
/*                     GDALSerializeGCPListToXML()                      */
4819
/************************************************************************/
4820
4821
void GDALSerializeGCPListToXML(CPLXMLNode *psParentNode,
4822
                               const std::vector<gdal::GCP> &asGCPs,
4823
                               const OGRSpatialReference *poGCP_SRS)
4824
9.05k
{
4825
9.05k
    CPLString oFmt;
4826
4827
9.05k
    CPLXMLNode *psPamGCPList =
4828
9.05k
        CPLCreateXMLNode(psParentNode, CXT_Element, "GCPList");
4829
4830
9.05k
    CPLXMLNode *psLastChild = nullptr;
4831
4832
9.05k
    if (poGCP_SRS != nullptr && !poGCP_SRS->IsEmpty())
4833
8.16k
    {
4834
8.16k
        char *pszWKT = nullptr;
4835
8.16k
        poGCP_SRS->exportToWkt(&pszWKT);
4836
8.16k
        CPLSetXMLValue(psPamGCPList, "#Projection", pszWKT);
4837
8.16k
        CPLFree(pszWKT);
4838
8.16k
        const auto &mapping = poGCP_SRS->GetDataAxisToSRSAxisMapping();
4839
8.16k
        CPLString osMapping;
4840
24.7k
        for (size_t i = 0; i < mapping.size(); ++i)
4841
16.5k
        {
4842
16.5k
            if (!osMapping.empty())
4843
8.38k
                osMapping += ",";
4844
16.5k
            osMapping += CPLSPrintf("%d", mapping[i]);
4845
16.5k
        }
4846
8.16k
        CPLSetXMLValue(psPamGCPList, "#dataAxisToSRSAxisMapping",
4847
8.16k
                       osMapping.c_str());
4848
4849
8.16k
        psLastChild = psPamGCPList->psChild->psNext;
4850
8.16k
    }
4851
4852
9.05k
    for (const gdal::GCP &gcp : asGCPs)
4853
93.3k
    {
4854
93.3k
        CPLXMLNode *psXMLGCP = CPLCreateXMLNode(nullptr, CXT_Element, "GCP");
4855
4856
93.3k
        if (psLastChild == nullptr)
4857
891
            psPamGCPList->psChild = psXMLGCP;
4858
92.4k
        else
4859
92.4k
            psLastChild->psNext = psXMLGCP;
4860
93.3k
        psLastChild = psXMLGCP;
4861
4862
93.3k
        CPLSetXMLValue(psXMLGCP, "#Id", gcp.Id());
4863
4864
93.3k
        if (gcp.Info() != nullptr && strlen(gcp.Info()) > 0)
4865
0
            CPLSetXMLValue(psXMLGCP, "Info", gcp.Info());
4866
4867
93.3k
        CPLSetXMLValue(psXMLGCP, "#Pixel", oFmt.Printf("%.4f", gcp.Pixel()));
4868
4869
93.3k
        CPLSetXMLValue(psXMLGCP, "#Line", oFmt.Printf("%.4f", gcp.Line()));
4870
4871
93.3k
        CPLSetXMLValue(psXMLGCP, "#X", oFmt.Printf("%.12E", gcp.X()));
4872
4873
93.3k
        CPLSetXMLValue(psXMLGCP, "#Y", oFmt.Printf("%.12E", gcp.Y()));
4874
4875
93.3k
        if (gcp.Z() != 0.0)
4876
81.7k
            CPLSetXMLValue(psXMLGCP, "#Z", oFmt.Printf("%.12E", gcp.Z()));
4877
93.3k
    }
4878
9.05k
}
4879
4880
/************************************************************************/
4881
/*                   GDALDeserializeGCPListFromXML()                    */
4882
/************************************************************************/
4883
4884
void GDALDeserializeGCPListFromXML(const CPLXMLNode *psGCPList,
4885
                                   std::vector<gdal::GCP> &asGCPs,
4886
                                   OGRSpatialReference **ppoGCP_SRS)
4887
13.2k
{
4888
13.2k
    if (ppoGCP_SRS)
4889
13.2k
    {
4890
13.2k
        const char *pszRawProj =
4891
13.2k
            CPLGetXMLValue(psGCPList, "Projection", nullptr);
4892
4893
13.2k
        *ppoGCP_SRS = nullptr;
4894
13.2k
        if (pszRawProj && pszRawProj[0])
4895
13.0k
        {
4896
13.0k
            *ppoGCP_SRS = new OGRSpatialReference();
4897
13.0k
            (*ppoGCP_SRS)
4898
13.0k
                ->SetFromUserInput(
4899
13.0k
                    pszRawProj,
4900
13.0k
                    OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS);
4901
4902
13.0k
            const char *pszMapping =
4903
13.0k
                CPLGetXMLValue(psGCPList, "dataAxisToSRSAxisMapping", nullptr);
4904
13.0k
            if (pszMapping)
4905
34
            {
4906
34
                char **papszTokens =
4907
34
                    CSLTokenizeStringComplex(pszMapping, ",", FALSE, FALSE);
4908
34
                std::vector<int> anMapping;
4909
102
                for (int i = 0; papszTokens && papszTokens[i]; i++)
4910
68
                {
4911
68
                    anMapping.push_back(atoi(papszTokens[i]));
4912
68
                }
4913
34
                CSLDestroy(papszTokens);
4914
34
                (*ppoGCP_SRS)->SetDataAxisToSRSAxisMapping(anMapping);
4915
34
            }
4916
13.0k
            else
4917
13.0k
            {
4918
13.0k
                (*ppoGCP_SRS)
4919
13.0k
                    ->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
4920
13.0k
            }
4921
13.0k
        }
4922
13.2k
    }
4923
4924
13.2k
    asGCPs.clear();
4925
77.0k
    for (const CPLXMLNode *psXMLGCP = psGCPList->psChild; psXMLGCP;
4926
63.7k
         psXMLGCP = psXMLGCP->psNext)
4927
63.7k
    {
4928
63.7k
        if (!EQUAL(psXMLGCP->pszValue, "GCP") || psXMLGCP->eType != CXT_Element)
4929
38.3k
            continue;
4930
4931
25.3k
        gdal::GCP gcp;
4932
25.3k
        gcp.SetId(CPLGetXMLValue(psXMLGCP, "Id", ""));
4933
25.3k
        gcp.SetInfo(CPLGetXMLValue(psXMLGCP, "Info", ""));
4934
4935
25.3k
        const auto ParseDoubleValue =
4936
25.3k
            [psXMLGCP](const char *pszParameter, double &dfVal)
4937
101k
        {
4938
101k
            const char *pszVal =
4939
101k
                CPLGetXMLValue(psXMLGCP, pszParameter, nullptr);
4940
101k
            if (!pszVal)
4941
78
            {
4942
78
                CPLError(CE_Failure, CPLE_AppDefined, "GCP#%s is missing",
4943
78
                         pszParameter);
4944
78
                return false;
4945
78
            }
4946
101k
            char *endptr = nullptr;
4947
101k
            dfVal = CPLStrtod(pszVal, &endptr);
4948
101k
            if (endptr == pszVal)
4949
20
            {
4950
20
                CPLError(CE_Failure, CPLE_AppDefined,
4951
20
                         "GCP#%s=%s is an invalid value", pszParameter, pszVal);
4952
20
                return false;
4953
20
            }
4954
101k
            return true;
4955
101k
        };
4956
4957
25.3k
        bool bOK = true;
4958
25.3k
        if (!ParseDoubleValue("Pixel", gcp.Pixel()))
4959
24
            bOK = false;
4960
25.3k
        if (!ParseDoubleValue("Line", gcp.Line()))
4961
16
            bOK = false;
4962
25.3k
        if (!ParseDoubleValue("X", gcp.X()))
4963
28
            bOK = false;
4964
25.3k
        if (!ParseDoubleValue("Y", gcp.Y()))
4965
30
            bOK = false;
4966
25.3k
        const char *pszZ = CPLGetXMLValue(psXMLGCP, "Z", nullptr);
4967
25.3k
        if (pszZ == nullptr)
4968
24.0k
        {
4969
            // Note: GDAL 1.10.1 and older generated #GCPZ,
4970
            // but could not read it back.
4971
24.0k
            pszZ = CPLGetXMLValue(psXMLGCP, "GCPZ", "0.0");
4972
24.0k
        }
4973
25.3k
        char *endptr = nullptr;
4974
25.3k
        gcp.Z() = CPLStrtod(pszZ, &endptr);
4975
25.3k
        if (endptr == pszZ)
4976
0
        {
4977
0
            CPLError(CE_Failure, CPLE_AppDefined,
4978
0
                     "GCP#Z=%s is an invalid value", pszZ);
4979
0
            bOK = false;
4980
0
        }
4981
4982
25.3k
        if (bOK)
4983
25.2k
        {
4984
25.2k
            asGCPs.emplace_back(std::move(gcp));
4985
25.2k
        }
4986
25.3k
    }
4987
13.2k
}
4988
4989
/************************************************************************/
4990
/*                   GDALSerializeOpenOptionsToXML()                    */
4991
/************************************************************************/
4992
4993
void GDALSerializeOpenOptionsToXML(CPLXMLNode *psParentNode,
4994
                                   CSLConstList papszOpenOptions)
4995
64.8k
{
4996
64.8k
    if (papszOpenOptions != nullptr)
4997
0
    {
4998
0
        CPLXMLNode *psOpenOptions =
4999
0
            CPLCreateXMLNode(psParentNode, CXT_Element, "OpenOptions");
5000
0
        CPLXMLNode *psLastChild = nullptr;
5001
5002
0
        for (CSLConstList papszIter = papszOpenOptions; *papszIter != nullptr;
5003
0
             papszIter++)
5004
0
        {
5005
0
            const char *pszRawValue;
5006
0
            char *pszKey = nullptr;
5007
0
            CPLXMLNode *psOOI;
5008
5009
0
            pszRawValue = CPLParseNameValue(*papszIter, &pszKey);
5010
5011
0
            psOOI = CPLCreateXMLNode(nullptr, CXT_Element, "OOI");
5012
0
            if (psLastChild == nullptr)
5013
0
                psOpenOptions->psChild = psOOI;
5014
0
            else
5015
0
                psLastChild->psNext = psOOI;
5016
0
            psLastChild = psOOI;
5017
5018
0
            CPLSetXMLValue(psOOI, "#key", pszKey);
5019
0
            CPLCreateXMLNode(psOOI, CXT_Text, pszRawValue);
5020
5021
0
            CPLFree(pszKey);
5022
0
        }
5023
0
    }
5024
64.8k
}
5025
5026
/************************************************************************/
5027
/*                 GDALDeserializeOpenOptionsFromXML()                  */
5028
/************************************************************************/
5029
5030
char **GDALDeserializeOpenOptionsFromXML(const CPLXMLNode *psParentNode)
5031
87.5k
{
5032
87.5k
    char **papszOpenOptions = nullptr;
5033
87.5k
    const CPLXMLNode *psOpenOptions =
5034
87.5k
        CPLGetXMLNode(psParentNode, "OpenOptions");
5035
87.5k
    if (psOpenOptions != nullptr)
5036
0
    {
5037
0
        const CPLXMLNode *psOOI;
5038
0
        for (psOOI = psOpenOptions->psChild; psOOI != nullptr;
5039
0
             psOOI = psOOI->psNext)
5040
0
        {
5041
0
            if (!EQUAL(psOOI->pszValue, "OOI") || psOOI->eType != CXT_Element ||
5042
0
                psOOI->psChild == nullptr ||
5043
0
                psOOI->psChild->psNext == nullptr ||
5044
0
                psOOI->psChild->eType != CXT_Attribute ||
5045
0
                psOOI->psChild->psChild == nullptr)
5046
0
                continue;
5047
5048
0
            char *pszName = psOOI->psChild->psChild->pszValue;
5049
0
            char *pszValue = psOOI->psChild->psNext->pszValue;
5050
0
            if (pszName != nullptr && pszValue != nullptr)
5051
0
                papszOpenOptions =
5052
0
                    CSLSetNameValue(papszOpenOptions, pszName, pszValue);
5053
0
        }
5054
0
    }
5055
87.5k
    return papszOpenOptions;
5056
87.5k
}
5057
5058
/************************************************************************/
5059
/*                     GDALRasterIOGetResampleAlg()                     */
5060
/************************************************************************/
5061
5062
GDALRIOResampleAlg GDALRasterIOGetResampleAlg(const char *pszResampling)
5063
64.5k
{
5064
64.5k
    GDALRIOResampleAlg eResampleAlg = GRIORA_NearestNeighbour;
5065
64.5k
    if (STARTS_WITH_CI(pszResampling, "NEAR"))
5066
11.1k
        eResampleAlg = GRIORA_NearestNeighbour;
5067
53.3k
    else if (EQUAL(pszResampling, "BILINEAR"))
5068
0
        eResampleAlg = GRIORA_Bilinear;
5069
53.3k
    else if (EQUAL(pszResampling, "CUBIC"))
5070
7.34k
        eResampleAlg = GRIORA_Cubic;
5071
46.0k
    else if (EQUAL(pszResampling, "CUBICSPLINE"))
5072
0
        eResampleAlg = GRIORA_CubicSpline;
5073
46.0k
    else if (EQUAL(pszResampling, "LANCZOS"))
5074
14.2k
        eResampleAlg = GRIORA_Lanczos;
5075
31.7k
    else if (EQUAL(pszResampling, "AVERAGE"))
5076
14.7k
        eResampleAlg = GRIORA_Average;
5077
16.9k
    else if (EQUAL(pszResampling, "RMS"))
5078
4
        eResampleAlg = GRIORA_RMS;
5079
16.9k
    else if (EQUAL(pszResampling, "MODE"))
5080
0
        eResampleAlg = GRIORA_Mode;
5081
16.9k
    else if (EQUAL(pszResampling, "GAUSS"))
5082
7.04k
        eResampleAlg = GRIORA_Gauss;
5083
9.93k
    else
5084
9.93k
        CPLError(CE_Warning, CPLE_NotSupported,
5085
9.93k
                 "GDAL_RASTERIO_RESAMPLING = %s not supported", pszResampling);
5086
64.5k
    return eResampleAlg;
5087
64.5k
}
5088
5089
/************************************************************************/
5090
/*                   GDALRasterIOGetResampleAlgStr()                    */
5091
/************************************************************************/
5092
5093
const char *GDALRasterIOGetResampleAlg(GDALRIOResampleAlg eResampleAlg)
5094
35.3k
{
5095
35.3k
    const char *pszRet = "Unknown";
5096
35.3k
    switch (eResampleAlg)
5097
35.3k
    {
5098
0
        case GRIORA_NearestNeighbour:
5099
0
            pszRet = "NearestNeighbour";
5100
0
            break;
5101
0
        case GRIORA_Bilinear:
5102
0
            return "Bilinear";
5103
5.53k
        case GRIORA_Cubic:
5104
5.53k
            return "Cubic";
5105
0
        case GRIORA_CubicSpline:
5106
0
            return "CubicSpline";
5107
10.2k
        case GRIORA_Lanczos:
5108
10.2k
            return "Lanczos";
5109
14.6k
        case GRIORA_Average:
5110
14.6k
            return "Average";
5111
5
        case GRIORA_RMS:
5112
5
            return "RMS";
5113
0
        case GRIORA_Mode:
5114
0
            return "Mode";
5115
4.86k
        case GRIORA_Gauss:
5116
4.86k
            return "Gauss";
5117
0
        case GRIORA_RESERVED_START:
5118
0
        case GRIORA_RESERVED_END:
5119
0
            break;
5120
35.3k
    }
5121
0
    return pszRet;
5122
35.3k
}
5123
5124
/************************************************************************/
5125
/*                 GDALRasterIOExtraArgSetResampleAlg()                 */
5126
/************************************************************************/
5127
5128
void GDALRasterIOExtraArgSetResampleAlg(GDALRasterIOExtraArg *psExtraArg,
5129
                                        int nXSize, int nYSize, int nBufXSize,
5130
                                        int nBufYSize)
5131
32.1M
{
5132
32.1M
    if ((nBufXSize != nXSize || nBufYSize != nYSize) &&
5133
346k
        psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
5134
310k
    {
5135
310k
        const char *pszResampling =
5136
310k
            CPLGetConfigOption("GDAL_RASTERIO_RESAMPLING", nullptr);
5137
310k
        if (pszResampling != nullptr)
5138
0
        {
5139
0
            psExtraArg->eResampleAlg =
5140
0
                GDALRasterIOGetResampleAlg(pszResampling);
5141
0
        }
5142
310k
    }
5143
32.1M
}
5144
5145
/************************************************************************/
5146
/*                    GDALCanFileAcceptSidecarFile()                    */
5147
/************************************************************************/
5148
5149
int GDALCanFileAcceptSidecarFile(const char *pszFilename)
5150
2.29M
{
5151
2.29M
    if (strstr(pszFilename, "/vsicurl/") && strchr(pszFilename, '?'))
5152
2.53k
        return FALSE;
5153
    // Do no attempt reading side-car files on /vsisubfile/ (#6241)
5154
2.28M
    if (strncmp(pszFilename, "/vsisubfile/", strlen("/vsisubfile/")) == 0)
5155
1
        return FALSE;
5156
2.28M
    return TRUE;
5157
2.28M
}
5158
5159
/************************************************************************/
5160
/*                 GDALCanReliablyUseSiblingFileList()                  */
5161
/************************************************************************/
5162
5163
/* Try to address https://github.com/OSGeo/gdal/issues/2903 */
5164
/* - On Apple HFS+ filesystem, filenames are stored in a variant of UTF-8 NFD */
5165
/*   (normalization form decomposed). The filesystem takes care of converting */
5166
/*   precomposed form as often coming from user interface to this NFD variant */
5167
/*   See
5168
 * https://stackoverflow.com/questions/6153345/different-utf8-encoding-in-filenames-os-x
5169
 */
5170
/*   And readdir() will return such NFD variant encoding. Consequently comparing
5171
 */
5172
/*   the user filename with ones with readdir() is not reliable */
5173
/* - APFS preserves both case and normalization of the filename on disk in all
5174
 */
5175
/*   variants. In macOS High Sierra, APFS is normalization-insensitive in both
5176
 */
5177
/*   the case-insensitive and case-sensitive variants, using a hash-based native
5178
 */
5179
/*   normalization scheme. APFS preserves the normalization of the filename and
5180
 */
5181
/*   uses hashes of the normalized form of the filename to provide normalization
5182
 */
5183
/*   insensitivity. */
5184
/*   From
5185
 * https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html
5186
 */
5187
/*   Issues might still arise if the file has been created using one of the
5188
 * UTF-8 */
5189
/*   encoding (likely the decomposed one if using MacOS specific API), but the
5190
 */
5191
/*   string passed to GDAL for opening would be with another one (likely the
5192
 * precomposed one) */
5193
bool GDALCanReliablyUseSiblingFileList(const char *pszFilename)
5194
1.76M
{
5195
#ifdef __APPLE__
5196
    for (int i = 0; pszFilename[i] != 0; ++i)
5197
    {
5198
        if (reinterpret_cast<const unsigned char *>(pszFilename)[i] > 127)
5199
        {
5200
            // non-ASCII character found
5201
5202
            // if this is a network storage, assume no issue
5203
            if (!VSIIsLocal(pszFilename))
5204
            {
5205
                return true;
5206
            }
5207
            return false;
5208
        }
5209
    }
5210
    return true;
5211
#else
5212
1.76M
    (void)pszFilename;
5213
1.76M
    return true;
5214
1.76M
#endif
5215
1.76M
}
5216
5217
/************************************************************************/
5218
/*                  GDALAdjustNoDataCloseToFloatMax()                   */
5219
/************************************************************************/
5220
5221
double GDALAdjustNoDataCloseToFloatMax(double dfVal)
5222
9.04k
{
5223
9.04k
    const auto kMaxFloat = cpl::NumericLimits<float>::max();
5224
9.04k
    if (std::fabs(dfVal - -kMaxFloat) < 1e-10 * kMaxFloat)
5225
1
        return -kMaxFloat;
5226
9.04k
    if (std::fabs(dfVal - kMaxFloat) < 1e-10 * kMaxFloat)
5227
1
        return kMaxFloat;
5228
9.04k
    return dfVal;
5229
9.04k
}
5230
5231
/************************************************************************/
5232
/*                        GDALCopyNoDataValue()                         */
5233
/************************************************************************/
5234
5235
/** Copy the nodata value from the source band to the target band if
5236
 * it can be exactly represented in the output data type.
5237
 *
5238
 * @param poDstBand Destination band.
5239
 * @param poSrcBand Source band band.
5240
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
5241
 *             If the value cannot be exactly represented on the output data
5242
 *             type, *pbCannotBeExactlyRepresented will be set to true.
5243
 *
5244
 * @return true if the nodata value was successfully set.
5245
 */
5246
bool GDALCopyNoDataValue(GDALRasterBand *poDstBand, GDALRasterBand *poSrcBand,
5247
                         bool *pbCannotBeExactlyRepresented)
5248
107k
{
5249
107k
    if (pbCannotBeExactlyRepresented)
5250
29.1k
        *pbCannotBeExactlyRepresented = false;
5251
107k
    int bSuccess;
5252
107k
    const auto eSrcDataType = poSrcBand->GetRasterDataType();
5253
107k
    const auto eDstDataType = poDstBand->GetRasterDataType();
5254
107k
    if (eSrcDataType == GDT_Int64)
5255
4
    {
5256
4
        const auto nNoData = poSrcBand->GetNoDataValueAsInt64(&bSuccess);
5257
4
        if (bSuccess)
5258
0
        {
5259
0
            if (eDstDataType == GDT_Int64)
5260
0
            {
5261
0
                return poDstBand->SetNoDataValueAsInt64(nNoData) == CE_None;
5262
0
            }
5263
0
            else if (eDstDataType == GDT_UInt64)
5264
0
            {
5265
0
                if (nNoData >= 0)
5266
0
                {
5267
0
                    return poDstBand->SetNoDataValueAsUInt64(
5268
0
                               static_cast<uint64_t>(nNoData)) == CE_None;
5269
0
                }
5270
0
            }
5271
0
            else if (nNoData ==
5272
0
                     static_cast<int64_t>(static_cast<double>(nNoData)))
5273
0
            {
5274
0
                const double dfValue = static_cast<double>(nNoData);
5275
0
                if (GDALIsValueExactAs(dfValue, eDstDataType))
5276
0
                    return poDstBand->SetNoDataValue(dfValue) == CE_None;
5277
0
            }
5278
0
        }
5279
4
    }
5280
107k
    else if (eSrcDataType == GDT_UInt64)
5281
904
    {
5282
904
        const auto nNoData = poSrcBand->GetNoDataValueAsUInt64(&bSuccess);
5283
904
        if (bSuccess)
5284
2
        {
5285
2
            if (eDstDataType == GDT_UInt64)
5286
2
            {
5287
2
                return poDstBand->SetNoDataValueAsUInt64(nNoData) == CE_None;
5288
2
            }
5289
0
            else if (eDstDataType == GDT_Int64)
5290
0
            {
5291
0
                if (nNoData <
5292
0
                    static_cast<uint64_t>(cpl::NumericLimits<int64_t>::max()))
5293
0
                {
5294
0
                    return poDstBand->SetNoDataValueAsInt64(
5295
0
                               static_cast<int64_t>(nNoData)) == CE_None;
5296
0
                }
5297
0
            }
5298
0
            else if (nNoData ==
5299
0
                     static_cast<uint64_t>(static_cast<double>(nNoData)))
5300
0
            {
5301
0
                const double dfValue = static_cast<double>(nNoData);
5302
0
                if (GDALIsValueExactAs(dfValue, eDstDataType))
5303
0
                    return poDstBand->SetNoDataValue(dfValue) == CE_None;
5304
0
            }
5305
2
        }
5306
904
    }
5307
106k
    else
5308
106k
    {
5309
106k
        const auto dfNoData = poSrcBand->GetNoDataValue(&bSuccess);
5310
106k
        if (bSuccess)
5311
39.1k
        {
5312
39.1k
            if (eDstDataType == GDT_Int64)
5313
0
            {
5314
0
                if (dfNoData >= static_cast<double>(
5315
0
                                    cpl::NumericLimits<int64_t>::lowest()) &&
5316
0
                    dfNoData <= static_cast<double>(
5317
0
                                    cpl::NumericLimits<int64_t>::max()) &&
5318
0
                    dfNoData ==
5319
0
                        static_cast<double>(static_cast<int64_t>(dfNoData)))
5320
0
                {
5321
0
                    return poDstBand->SetNoDataValueAsInt64(
5322
0
                               static_cast<int64_t>(dfNoData)) == CE_None;
5323
0
                }
5324
0
            }
5325
39.1k
            else if (eDstDataType == GDT_UInt64)
5326
0
            {
5327
0
                if (dfNoData >= static_cast<double>(
5328
0
                                    cpl::NumericLimits<uint64_t>::lowest()) &&
5329
0
                    dfNoData <= static_cast<double>(
5330
0
                                    cpl::NumericLimits<uint64_t>::max()) &&
5331
0
                    dfNoData ==
5332
0
                        static_cast<double>(static_cast<uint64_t>(dfNoData)))
5333
0
                {
5334
0
                    return poDstBand->SetNoDataValueAsInt64(
5335
0
                               static_cast<uint64_t>(dfNoData)) == CE_None;
5336
0
                }
5337
0
            }
5338
39.1k
            else
5339
39.1k
            {
5340
39.1k
                return poDstBand->SetNoDataValue(dfNoData) == CE_None;
5341
39.1k
            }
5342
39.1k
        }
5343
106k
    }
5344
68.2k
    if (pbCannotBeExactlyRepresented)
5345
0
        *pbCannotBeExactlyRepresented = true;
5346
68.2k
    return false;
5347
107k
}
5348
5349
/************************************************************************/
5350
/*                   GDALGetNoDataValueCastToDouble()                   */
5351
/************************************************************************/
5352
5353
double GDALGetNoDataValueCastToDouble(int64_t nVal)
5354
116
{
5355
116
    const double dfVal = static_cast<double>(nVal);
5356
116
    if (static_cast<int64_t>(dfVal) != nVal)
5357
5
    {
5358
5
        CPLError(CE_Warning, CPLE_AppDefined,
5359
5
                 "GetNoDataValue() returns an approximate value of the "
5360
5
                 "true nodata value = " CPL_FRMT_GIB ". Use "
5361
5
                 "GetNoDataValueAsInt64() instead",
5362
5
                 static_cast<GIntBig>(nVal));
5363
5
    }
5364
116
    return dfVal;
5365
116
}
5366
5367
double GDALGetNoDataValueCastToDouble(uint64_t nVal)
5368
135
{
5369
135
    const double dfVal = static_cast<double>(nVal);
5370
135
    if (static_cast<uint64_t>(dfVal) != nVal)
5371
13
    {
5372
13
        CPLError(CE_Warning, CPLE_AppDefined,
5373
13
                 "GetNoDataValue() returns an approximate value of the "
5374
13
                 "true nodata value = " CPL_FRMT_GUIB ". Use "
5375
13
                 "GetNoDataValueAsUInt64() instead",
5376
13
                 static_cast<GUIntBig>(nVal));
5377
13
    }
5378
135
    return dfVal;
5379
135
}
5380
5381
/************************************************************************/
5382
/*                  GDALGetCompressionFormatForJPEG()                   */
5383
/************************************************************************/
5384
5385
//! @cond Doxygen_Suppress
5386
std::string GDALGetCompressionFormatForJPEG(VSILFILE *fp)
5387
0
{
5388
0
    std::string osRet;
5389
0
    const auto nSavedPos = VSIFTellL(fp);
5390
0
    GByte abyMarkerHeader[4];
5391
0
    if (VSIFSeekL(fp, 0, SEEK_SET) == 0 &&
5392
0
        VSIFReadL(abyMarkerHeader, 2, 1, fp) == 1 &&
5393
0
        abyMarkerHeader[0] == 0xFF && abyMarkerHeader[1] == 0xD8)
5394
0
    {
5395
0
        osRet = "JPEG";
5396
0
        bool bHasAPP14Adobe = false;
5397
0
        GByte abyAPP14AdobeMarkerData[14 - 2] = {0};
5398
0
        int nNumComponents = 0;
5399
0
        while (true)
5400
0
        {
5401
0
            const auto nCurPos = VSIFTellL(fp);
5402
0
            if (VSIFReadL(abyMarkerHeader, 4, 1, fp) != 1)
5403
0
                break;
5404
0
            if (abyMarkerHeader[0] != 0xFF)
5405
0
                break;
5406
0
            const GByte markerType = abyMarkerHeader[1];
5407
0
            const size_t nMarkerSize =
5408
0
                abyMarkerHeader[2] * 256 + abyMarkerHeader[3];
5409
0
            if (nMarkerSize < 2)
5410
0
                break;
5411
0
            if (markerType >= 0xC0 && markerType <= 0xCF &&
5412
0
                markerType != 0xC4 && markerType != 0xC8 && markerType != 0xCC)
5413
0
            {
5414
0
                switch (markerType)
5415
0
                {
5416
0
                    case 0xC0:
5417
0
                        osRet += ";frame_type=SOF0_baseline";
5418
0
                        break;
5419
0
                    case 0xC1:
5420
0
                        osRet += ";frame_type=SOF1_extended_sequential";
5421
0
                        break;
5422
0
                    case 0xC2:
5423
0
                        osRet += ";frame_type=SOF2_progressive_huffman";
5424
0
                        break;
5425
0
                    case 0xC3:
5426
0
                        osRet += ";frame_type=SOF3_lossless_huffman;libjpeg_"
5427
0
                                 "supported=no";
5428
0
                        break;
5429
0
                    case 0xC5:
5430
0
                        osRet += ";frame_type="
5431
0
                                 "SOF5_differential_sequential_huffman;"
5432
0
                                 "libjpeg_supported=no";
5433
0
                        break;
5434
0
                    case 0xC6:
5435
0
                        osRet += ";frame_type=SOF6_differential_progressive_"
5436
0
                                 "huffman;libjpeg_supported=no";
5437
0
                        break;
5438
0
                    case 0xC7:
5439
0
                        osRet += ";frame_type="
5440
0
                                 "SOF7_differential_lossless_huffman;"
5441
0
                                 "libjpeg_supported=no";
5442
0
                        break;
5443
0
                    case 0xC9:
5444
0
                        osRet += ";frame_type="
5445
0
                                 "SOF9_extended_sequential_arithmetic";
5446
0
                        break;
5447
0
                    case 0xCA:
5448
0
                        osRet += ";frame_type=SOF10_progressive_arithmetic";
5449
0
                        break;
5450
0
                    case 0xCB:
5451
0
                        osRet += ";frame_type="
5452
0
                                 "SOF11_lossless_arithmetic;libjpeg_"
5453
0
                                 "supported=no";
5454
0
                        break;
5455
0
                    case 0xCD:
5456
0
                        osRet += ";frame_type=SOF13_differential_sequential_"
5457
0
                                 "arithmetic;libjpeg_supported=no";
5458
0
                        break;
5459
0
                    case 0xCE:
5460
0
                        osRet += ";frame_type=SOF14_differential_progressive_"
5461
0
                                 "arithmetic;libjpeg_supported=no";
5462
0
                        break;
5463
0
                    case 0xCF:
5464
0
                        osRet += ";frame_type=SOF15_differential_lossless_"
5465
0
                                 "arithmetic;libjpeg_supported=no";
5466
0
                        break;
5467
0
                    default:
5468
0
                        break;
5469
0
                }
5470
0
                GByte abySegmentBegin[6];
5471
0
                if (VSIFReadL(abySegmentBegin, sizeof(abySegmentBegin), 1,
5472
0
                              fp) != 1)
5473
0
                    break;
5474
0
                osRet += ";bit_depth=";
5475
0
                osRet += CPLSPrintf("%d", abySegmentBegin[0]);
5476
0
                nNumComponents = abySegmentBegin[5];
5477
0
                osRet += ";num_components=";
5478
0
                osRet += CPLSPrintf("%d", nNumComponents);
5479
0
                if (nNumComponents == 3)
5480
0
                {
5481
0
                    GByte abySegmentNext[3 * 3];
5482
0
                    if (VSIFReadL(abySegmentNext, sizeof(abySegmentNext), 1,
5483
0
                                  fp) != 1)
5484
0
                        break;
5485
0
                    if (abySegmentNext[0] == 1 && abySegmentNext[1] == 0x11 &&
5486
0
                        abySegmentNext[3] == 2 && abySegmentNext[4] == 0x11 &&
5487
0
                        abySegmentNext[6] == 3 && abySegmentNext[7] == 0x11)
5488
0
                    {
5489
                        // no subsampling
5490
0
                        osRet += ";subsampling=4:4:4";
5491
0
                    }
5492
0
                    else if (abySegmentNext[0] == 1 &&
5493
0
                             abySegmentNext[1] == 0x22 &&
5494
0
                             abySegmentNext[3] == 2 &&
5495
0
                             abySegmentNext[4] == 0x11 &&
5496
0
                             abySegmentNext[6] == 3 &&
5497
0
                             abySegmentNext[7] == 0x11)
5498
0
                    {
5499
                        // classic subsampling
5500
0
                        osRet += ";subsampling=4:2:0";
5501
0
                    }
5502
0
                    else if (abySegmentNext[0] == 1 &&
5503
0
                             abySegmentNext[1] == 0x21 &&
5504
0
                             abySegmentNext[3] == 2 &&
5505
0
                             abySegmentNext[4] == 0x11 &&
5506
0
                             abySegmentNext[6] == 3 &&
5507
0
                             abySegmentNext[7] == 0x11)
5508
0
                    {
5509
0
                        osRet += ";subsampling=4:2:2";
5510
0
                    }
5511
0
                }
5512
0
            }
5513
0
            else if (markerType == 0xEE && nMarkerSize == 14)
5514
0
            {
5515
0
                if (VSIFReadL(abyAPP14AdobeMarkerData,
5516
0
                              sizeof(abyAPP14AdobeMarkerData), 1, fp) == 1 &&
5517
0
                    memcmp(abyAPP14AdobeMarkerData, "Adobe", strlen("Adobe")) ==
5518
0
                        0)
5519
0
                {
5520
0
                    bHasAPP14Adobe = true;
5521
0
                }
5522
0
            }
5523
0
            else if (markerType == 0xDA)
5524
0
            {
5525
                // Start of scan
5526
0
                break;
5527
0
            }
5528
0
            VSIFSeekL(fp, nCurPos + nMarkerSize + 2, SEEK_SET);
5529
0
        }
5530
0
        std::string osColorspace;
5531
0
        if (bHasAPP14Adobe)
5532
0
        {
5533
0
            if (abyAPP14AdobeMarkerData[11] == 0)
5534
0
            {
5535
0
                if (nNumComponents == 3)
5536
0
                    osColorspace = "RGB";
5537
0
                else if (nNumComponents == 4)
5538
0
                    osColorspace = "CMYK";
5539
0
            }
5540
0
            else if (abyAPP14AdobeMarkerData[11] == 1)
5541
0
            {
5542
0
                osColorspace = "YCbCr";
5543
0
            }
5544
0
            else if (abyAPP14AdobeMarkerData[11] == 2)
5545
0
            {
5546
0
                osColorspace = "YCCK";
5547
0
            }
5548
0
        }
5549
0
        else
5550
0
        {
5551
0
            if (nNumComponents == 3)
5552
0
                osColorspace = "YCbCr";
5553
0
            else if (nNumComponents == 4)
5554
0
                osColorspace = "CMYK";
5555
0
        }
5556
0
        osRet += ";colorspace=";
5557
0
        if (!osColorspace.empty())
5558
0
            osRet += osColorspace;
5559
0
        else
5560
0
            osRet += "unknown";
5561
0
    }
5562
0
    if (VSIFSeekL(fp, nSavedPos, SEEK_SET) != 0)
5563
0
    {
5564
0
        CPLError(CE_Failure, CPLE_AppDefined,
5565
0
                 "VSIFSeekL(fp, nSavedPos, SEEK_SET) failed");
5566
0
    }
5567
0
    return osRet;
5568
0
}
5569
5570
std::string GDALGetCompressionFormatForJPEG(const void *pBuffer,
5571
                                            size_t nBufferSize)
5572
0
{
5573
0
    VSILFILE *fp = VSIFileFromMemBuffer(
5574
0
        nullptr, static_cast<GByte *>(const_cast<void *>(pBuffer)), nBufferSize,
5575
0
        false);
5576
0
    std::string osRet = GDALGetCompressionFormatForJPEG(fp);
5577
0
    VSIFCloseL(fp);
5578
0
    return osRet;
5579
0
}
5580
5581
//! @endcond
5582
5583
/************************************************************************/
5584
/*                   GDALGetNoDataReplacementValue()                    */
5585
/************************************************************************/
5586
5587
/**
5588
 * \brief Returns a replacement value for a nodata value or 0 if dfNoDataValue
5589
 *        is out of range for the specified data type (dt).
5590
 *        For UInt64 and Int64 data type this function cannot reliably trusted
5591
 *        because their nodata values might not always be representable exactly
5592
 *        as a double, in particular the maximum absolute value for those types
5593
 *        is 2^53.
5594
 *
5595
 * The replacement value is a value that can be used in a computation
5596
 * whose result would match by accident the nodata value, whereas it is
5597
 * meant to be valid. For example, for a dataset with a nodata value of 0,
5598
 * when averaging -1 and 1, one would get normally a value of 0. The
5599
 * replacement nodata value can then be substituted to that 0 value to still
5600
 * get a valid value, as close as practical to the true value, while being
5601
 * different from the nodata value.
5602
 *
5603
 * @param dt Data type
5604
 * @param dfNoDataValue The no data value
5605
5606
 * @since GDAL 3.9
5607
 */
5608
double GDALGetNoDataReplacementValue(GDALDataType dt, double dfNoDataValue)
5609
9.82k
{
5610
5611
    // The logic here is to check if the value is out of range for the
5612
    // specified data type and return a replacement value if it is, return
5613
    // 0 otherwise.
5614
9.82k
    double dfReplacementVal = dfNoDataValue;
5615
9.82k
    if (dt == GDT_UInt8)
5616
1.99k
    {
5617
1.99k
        if (GDALClampDoubleValue(dfNoDataValue,
5618
1.99k
                                 cpl::NumericLimits<uint8_t>::lowest(),
5619
1.99k
                                 cpl::NumericLimits<uint8_t>::max()))
5620
536
        {
5621
536
            return 0;
5622
536
        }
5623
1.45k
        if (dfNoDataValue == cpl::NumericLimits<unsigned char>::max())
5624
0
            dfReplacementVal = cpl::NumericLimits<unsigned char>::max() - 1;
5625
1.45k
        else
5626
1.45k
            dfReplacementVal = dfNoDataValue + 1;
5627
1.45k
    }
5628
7.83k
    else if (dt == GDT_Int8)
5629
43
    {
5630
43
        if (GDALClampDoubleValue(dfNoDataValue,
5631
43
                                 cpl::NumericLimits<int8_t>::lowest(),
5632
43
                                 cpl::NumericLimits<int8_t>::max()))
5633
2
        {
5634
2
            return 0;
5635
2
        }
5636
41
        if (dfNoDataValue == cpl::NumericLimits<GInt8>::max())
5637
0
            dfReplacementVal = cpl::NumericLimits<GInt8>::max() - 1;
5638
41
        else
5639
41
            dfReplacementVal = dfNoDataValue + 1;
5640
41
    }
5641
7.79k
    else if (dt == GDT_UInt16)
5642
75
    {
5643
75
        if (GDALClampDoubleValue(dfNoDataValue,
5644
75
                                 cpl::NumericLimits<uint16_t>::lowest(),
5645
75
                                 cpl::NumericLimits<uint16_t>::max()))
5646
0
        {
5647
0
            return 0;
5648
0
        }
5649
75
        if (dfNoDataValue == cpl::NumericLimits<GUInt16>::max())
5650
0
            dfReplacementVal = cpl::NumericLimits<GUInt16>::max() - 1;
5651
75
        else
5652
75
            dfReplacementVal = dfNoDataValue + 1;
5653
75
    }
5654
7.71k
    else if (dt == GDT_Int16)
5655
4.28k
    {
5656
4.28k
        if (GDALClampDoubleValue(dfNoDataValue,
5657
4.28k
                                 cpl::NumericLimits<int16_t>::lowest(),
5658
4.28k
                                 cpl::NumericLimits<int16_t>::max()))
5659
0
        {
5660
0
            return 0;
5661
0
        }
5662
4.28k
        if (dfNoDataValue == cpl::NumericLimits<GInt16>::max())
5663
4.27k
            dfReplacementVal = cpl::NumericLimits<GInt16>::max() - 1;
5664
6
        else
5665
6
            dfReplacementVal = dfNoDataValue + 1;
5666
4.28k
    }
5667
3.43k
    else if (dt == GDT_UInt32)
5668
0
    {
5669
0
        if (GDALClampDoubleValue(dfNoDataValue,
5670
0
                                 cpl::NumericLimits<uint32_t>::lowest(),
5671
0
                                 cpl::NumericLimits<uint32_t>::max()))
5672
0
        {
5673
0
            return 0;
5674
0
        }
5675
0
        if (dfNoDataValue == cpl::NumericLimits<GUInt32>::max())
5676
0
            dfReplacementVal = cpl::NumericLimits<GUInt32>::max() - 1;
5677
0
        else
5678
0
            dfReplacementVal = dfNoDataValue + 1;
5679
0
    }
5680
3.43k
    else if (dt == GDT_Int32)
5681
228
    {
5682
228
        if (GDALClampDoubleValue(dfNoDataValue,
5683
228
                                 cpl::NumericLimits<int32_t>::lowest(),
5684
228
                                 cpl::NumericLimits<int32_t>::max()))
5685
0
        {
5686
0
            return 0;
5687
0
        }
5688
228
        if (dfNoDataValue == cpl::NumericLimits<int32_t>::max())
5689
0
            dfReplacementVal = cpl::NumericLimits<int32_t>::max() - 1;
5690
228
        else
5691
228
            dfReplacementVal = dfNoDataValue + 1;
5692
228
    }
5693
3.20k
    else if (dt == GDT_UInt64)
5694
0
    {
5695
        // Implicit conversion from 'unsigned long' to 'double' changes value from 18446744073709551615 to 18446744073709551616
5696
        // so we take the next lower value representable as a double 18446744073709549567
5697
0
        static const double dfMaxUInt64Value{
5698
0
            std::nextafter(
5699
0
                static_cast<double>(cpl::NumericLimits<uint64_t>::max()), 0) -
5700
0
            1};
5701
5702
0
        if (GDALClampDoubleValue(dfNoDataValue,
5703
0
                                 cpl::NumericLimits<uint64_t>::lowest(),
5704
0
                                 cpl::NumericLimits<uint64_t>::max()))
5705
0
        {
5706
0
            return 0;
5707
0
        }
5708
5709
0
        if (dfNoDataValue >=
5710
0
            static_cast<double>(cpl::NumericLimits<uint64_t>::max()))
5711
0
            dfReplacementVal = dfMaxUInt64Value;
5712
0
        else
5713
0
            dfReplacementVal = dfNoDataValue + 1;
5714
0
    }
5715
3.20k
    else if (dt == GDT_Int64)
5716
0
    {
5717
        // Implicit conversion from 'long' to 'double' changes value from 9223372036854775807 to 9223372036854775808
5718
        // so we take the next lower value representable as a double 9223372036854774784
5719
0
        static const double dfMaxInt64Value{
5720
0
            std::nextafter(
5721
0
                static_cast<double>(cpl::NumericLimits<int64_t>::max()), 0) -
5722
0
            1};
5723
5724
0
        if (GDALClampDoubleValue(dfNoDataValue,
5725
0
                                 cpl::NumericLimits<int64_t>::lowest(),
5726
0
                                 cpl::NumericLimits<int64_t>::max()))
5727
0
        {
5728
0
            return 0;
5729
0
        }
5730
5731
0
        if (dfNoDataValue >=
5732
0
            static_cast<double>(cpl::NumericLimits<int64_t>::max()))
5733
0
            dfReplacementVal = dfMaxInt64Value;
5734
0
        else
5735
0
            dfReplacementVal = dfNoDataValue + 1;
5736
0
    }
5737
3.20k
    else if (dt == GDT_Float16)
5738
0
    {
5739
5740
0
        if (GDALClampDoubleValue(dfNoDataValue,
5741
0
                                 cpl::NumericLimits<GFloat16>::lowest(),
5742
0
                                 cpl::NumericLimits<GFloat16>::max()))
5743
0
        {
5744
0
            return 0;
5745
0
        }
5746
5747
0
        if (dfNoDataValue == cpl::NumericLimits<GFloat16>::max())
5748
0
        {
5749
0
            using std::nextafter;
5750
0
            dfReplacementVal =
5751
0
                nextafter(static_cast<GFloat16>(dfNoDataValue), GFloat16(0.0f));
5752
0
        }
5753
0
        else
5754
0
        {
5755
0
            using std::nextafter;
5756
0
            dfReplacementVal = nextafter(static_cast<GFloat16>(dfNoDataValue),
5757
0
                                         cpl::NumericLimits<GFloat16>::max());
5758
0
        }
5759
0
    }
5760
3.20k
    else if (dt == GDT_Float32)
5761
2.93k
    {
5762
5763
2.93k
        if (GDALClampDoubleValue(dfNoDataValue,
5764
2.93k
                                 cpl::NumericLimits<float>::lowest(),
5765
2.93k
                                 cpl::NumericLimits<float>::max()))
5766
0
        {
5767
0
            return 0;
5768
0
        }
5769
5770
2.93k
        if (dfNoDataValue == cpl::NumericLimits<float>::max())
5771
0
        {
5772
0
            dfReplacementVal =
5773
0
                std::nextafter(static_cast<float>(dfNoDataValue), 0.0f);
5774
0
        }
5775
2.93k
        else
5776
2.93k
        {
5777
2.93k
            dfReplacementVal = std::nextafter(static_cast<float>(dfNoDataValue),
5778
2.93k
                                              cpl::NumericLimits<float>::max());
5779
2.93k
        }
5780
2.93k
    }
5781
266
    else if (dt == GDT_Float64)
5782
266
    {
5783
266
        if (GDALClampDoubleValue(dfNoDataValue,
5784
266
                                 cpl::NumericLimits<double>::lowest(),
5785
266
                                 cpl::NumericLimits<double>::max()))
5786
0
        {
5787
0
            return 0;
5788
0
        }
5789
5790
266
        if (dfNoDataValue == cpl::NumericLimits<double>::max())
5791
0
        {
5792
0
            dfReplacementVal = std::nextafter(dfNoDataValue, 0.0);
5793
0
        }
5794
266
        else
5795
266
        {
5796
266
            dfReplacementVal = std::nextafter(
5797
266
                dfNoDataValue, cpl::NumericLimits<double>::max());
5798
266
        }
5799
266
    }
5800
5801
9.28k
    return dfReplacementVal;
5802
9.82k
}
5803
5804
/************************************************************************/
5805
/*                       GDALGetCacheDirectory()                        */
5806
/************************************************************************/
5807
5808
/** Return the root path of the GDAL cache.
5809
 *
5810
 * If the GDAL_CACHE_DIRECTORY configuration option is set, its value will
5811
 * be returned.
5812
 * Otherwise if the XDG_CACHE_HOME environment variable is set,
5813
 * ${XDG_CACHE_HOME}/.gdal will be returned.
5814
 * Otherwise ${HOME}/.gdal on Unix or$ ${USERPROFILE}/.gdal on Windows will
5815
 * be returned.
5816
 * Otherwise ${CPL_TMPDIR|TMPDIR|TEMP}/.gdal_${USERNAME|USER} will be returned.
5817
 * Otherwise empty string will be returned.
5818
 *
5819
 * @since GDAL 3.11
5820
 */
5821
std::string GDALGetCacheDirectory()
5822
1.95k
{
5823
1.95k
    if (const char *pszGDAL_CACHE_DIRECTORY =
5824
1.95k
            CPLGetConfigOption("GDAL_CACHE_DIRECTORY", nullptr))
5825
0
    {
5826
0
        return pszGDAL_CACHE_DIRECTORY;
5827
0
    }
5828
5829
1.95k
    if (const char *pszXDG_CACHE_HOME =
5830
1.95k
            CPLGetConfigOption("XDG_CACHE_HOME", nullptr))
5831
0
    {
5832
0
        return CPLFormFilenameSafe(pszXDG_CACHE_HOME, "gdal", nullptr);
5833
0
    }
5834
5835
#ifdef _WIN32
5836
    const char *pszHome = CPLGetConfigOption("USERPROFILE", nullptr);
5837
#else
5838
1.95k
    const char *pszHome = CPLGetConfigOption("HOME", nullptr);
5839
1.95k
#endif
5840
1.95k
    if (pszHome != nullptr)
5841
1.95k
    {
5842
1.95k
        return CPLFormFilenameSafe(pszHome, ".gdal", nullptr);
5843
1.95k
    }
5844
0
    else
5845
0
    {
5846
0
        const char *pszDir = CPLGetConfigOption("CPL_TMPDIR", nullptr);
5847
5848
0
        if (pszDir == nullptr)
5849
0
            pszDir = CPLGetConfigOption("TMPDIR", nullptr);
5850
5851
0
        if (pszDir == nullptr)
5852
0
            pszDir = CPLGetConfigOption("TEMP", nullptr);
5853
5854
0
        const char *pszUsername = CPLGetConfigOption("USERNAME", nullptr);
5855
0
        if (pszUsername == nullptr)
5856
0
            pszUsername = CPLGetConfigOption("USER", nullptr);
5857
5858
0
        if (pszDir != nullptr && pszUsername != nullptr)
5859
0
        {
5860
0
            return CPLFormFilenameSafe(
5861
0
                pszDir, CPLSPrintf(".gdal_%s", pszUsername), nullptr);
5862
0
        }
5863
0
    }
5864
0
    return std::string();
5865
1.95k
}
5866
5867
/************************************************************************/
5868
/*                     GDALDoesFileOrDatasetExist()                     */
5869
/************************************************************************/
5870
5871
/** Return whether a file already exists.
5872
 */
5873
bool GDALDoesFileOrDatasetExist(const char *pszName, const char **ppszType,
5874
                                GDALDriver **ppDriver)
5875
3
{
5876
3
    {
5877
3
        CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
5878
3
        GDALDriverH hDriver = GDALIdentifyDriver(pszName, nullptr);
5879
3
        if (hDriver)
5880
0
        {
5881
0
            if (ppszType)
5882
0
                *ppszType = "Dataset";
5883
0
            if (ppDriver)
5884
0
                *ppDriver = GDALDriver::FromHandle(hDriver);
5885
0
            return true;
5886
0
        }
5887
3
    }
5888
5889
3
    VSIStatBufL sStat;
5890
3
    if (VSIStatL(pszName, &sStat) == 0)
5891
0
    {
5892
0
        if (ppszType)
5893
0
            *ppszType = VSI_ISDIR(sStat.st_mode) ? "Directory" : "File";
5894
0
        return true;
5895
0
    }
5896
5897
3
    return false;
5898
3
}
5899
5900
/************************************************************************/
5901
/*                       GDALGeoTransform::Apply                        */
5902
/************************************************************************/
5903
5904
bool GDALGeoTransform::Apply(const OGREnvelope &env,
5905
                             GDALRasterWindow &window) const
5906
0
{
5907
0
    if (!IsAxisAligned())
5908
0
    {
5909
0
        return false;
5910
0
    }
5911
5912
0
    double dfLeft, dfRight, dfTop, dfBottom;
5913
0
    Apply(env.MinX, env.MinY, &dfLeft, &dfBottom);
5914
0
    Apply(env.MaxX, env.MaxY, &dfRight, &dfTop);
5915
5916
0
    if (dfLeft > dfRight)
5917
0
        std::swap(dfLeft, dfRight);
5918
0
    if (dfTop > dfBottom)
5919
0
        std::swap(dfTop, dfBottom);
5920
5921
0
    constexpr double EPSILON = 1e-5;
5922
0
    dfTop = std::floor(dfTop + EPSILON);
5923
0
    dfBottom = std::ceil(dfBottom - EPSILON);
5924
0
    dfLeft = std::floor(dfLeft + EPSILON);
5925
0
    dfRight = std::ceil(dfRight - EPSILON);
5926
5927
0
    if (!(dfLeft >= INT_MIN && dfLeft <= INT_MAX &&
5928
0
          dfRight - dfLeft <= INT_MAX && dfTop >= INT_MIN && dfTop <= INT_MAX &&
5929
0
          dfBottom - dfLeft <= INT_MAX))
5930
0
    {
5931
0
        return false;
5932
0
    }
5933
0
    window.nXOff = static_cast<int>(dfLeft);
5934
0
    window.nXSize = static_cast<int>(dfRight - dfLeft);
5935
0
    window.nYOff = static_cast<int>(dfTop);
5936
0
    window.nYSize = static_cast<int>(dfBottom - dfTop);
5937
5938
0
    return true;
5939
0
}
5940
5941
bool GDALGeoTransform::Apply(const GDALRasterWindow &window,
5942
                             OGREnvelope &env) const
5943
0
{
5944
0
    if (!IsAxisAligned())
5945
0
    {
5946
0
        return false;
5947
0
    }
5948
5949
0
    double dfLeft = window.nXOff;
5950
0
    double dfRight = window.nXOff + window.nXSize;
5951
0
    double dfTop = window.nYOff;
5952
0
    double dfBottom = window.nYOff + window.nYSize;
5953
5954
0
    Apply(dfLeft, dfBottom, &env.MinX, &env.MinY);
5955
0
    Apply(dfRight, dfTop, &env.MaxX, &env.MaxY);
5956
5957
0
    if (env.MaxX < env.MinX)
5958
0
        std::swap(env.MinX, env.MaxX);
5959
0
    if (env.MaxY < env.MinY)
5960
0
        std::swap(env.MinY, env.MaxY);
5961
5962
0
    return true;
5963
0
}
5964
5965
/************************************************************************/
5966
/*                        GDALGeoTransform::Init                        */
5967
/************************************************************************/
5968
5969
bool GDALGeoTransform::Init(const char *pszText, const char *pszSep)
5970
1.91k
{
5971
1.91k
    CPLStringList aosGeoTransform(
5972
1.91k
        CSLTokenizeString2(pszText, pszSep, CSLT_HONOURSTRINGS));
5973
1.91k
    if (aosGeoTransform.size() != 6)
5974
912
    {
5975
912
        return false;
5976
912
    }
5977
5978
7.01k
    for (int i = 0; i < 6; i++)
5979
6.01k
    {
5980
6.01k
        (*this)[i] = CPLAtof(aosGeoTransform[i]);
5981
6.01k
    }
5982
5983
1.00k
    return true;
5984
1.91k
}
5985
5986
/************************************************************************/
5987
/*                      GDALGeoTransform::ToString                      */
5988
/************************************************************************/
5989
5990
std::string GDALGeoTransform::ToString(const char *pszSep) const
5991
0
{
5992
0
    return CPLSPrintf("%.17g%s%.17g%s%.17g%s%.17g%s%.17g%s%.17g", (*this)[0],
5993
0
                      pszSep, (*this)[1], pszSep, (*this)[2], pszSep,
5994
0
                      (*this)[3], pszSep, (*this)[4], pszSep, (*this)[5]);
5995
0
}