Coverage Report

Created: 2025-08-11 09:23

/src/gdal/frmts/aigrid/gridlib.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  Arc/Info Binary Grid Translator
4
 * Purpose:  Grid file reading code.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Frank Warmerdam
9
 * Copyright (c) 2007-2010, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "aigrid.h"
15
16
#ifndef CPL_IGNORE_RET_VAL_INT_defined
17
#define CPL_IGNORE_RET_VAL_INT_defined
18
19
CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
20
25.4k
{
21
25.4k
}
22
#endif
23
24
/************************************************************************/
25
/*                    AIGProcessRaw32bitFloatBlock()                    */
26
/*                                                                      */
27
/*      Process a block using ``00'' (32 bit) raw format.               */
28
/************************************************************************/
29
30
static CPLErr AIGProcessRaw32BitFloatBlock(GByte *pabyCur, int nDataSize,
31
                                           int nMin, int nBlockXSize,
32
                                           int nBlockYSize, float *pafData)
33
34
98
{
35
98
    int i;
36
37
98
    (void)nMin;
38
98
    if (nDataSize < nBlockXSize * nBlockYSize * 4)
39
98
    {
40
98
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
41
98
        return CE_Failure;
42
98
    }
43
44
    /* -------------------------------------------------------------------- */
45
    /*      Collect raw data.                                               */
46
    /* -------------------------------------------------------------------- */
47
0
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
48
0
    {
49
0
        float fWork;
50
51
0
#ifdef CPL_LSB
52
0
        ((GByte *)&fWork)[3] = *(pabyCur++);
53
0
        ((GByte *)&fWork)[2] = *(pabyCur++);
54
0
        ((GByte *)&fWork)[1] = *(pabyCur++);
55
0
        ((GByte *)&fWork)[0] = *(pabyCur++);
56
#else
57
        ((GByte *)&fWork)[0] = *(pabyCur++);
58
        ((GByte *)&fWork)[1] = *(pabyCur++);
59
        ((GByte *)&fWork)[2] = *(pabyCur++);
60
        ((GByte *)&fWork)[3] = *(pabyCur++);
61
#endif
62
63
0
        pafData[i] = fWork;
64
0
    }
65
66
0
    return (CE_None);
67
98
}
68
69
/************************************************************************/
70
/*                      AIGProcessIntConstBlock()                       */
71
/*                                                                      */
72
/*      Process a block using ``00'' constant 32bit integer format.     */
73
/************************************************************************/
74
75
static CPLErr AIGProcessIntConstBlock(GByte *pabyCur, int nDataSize, int nMin,
76
                                      int nBlockXSize, int nBlockYSize,
77
                                      GInt32 *panData)
78
79
151
{
80
151
    int i;
81
82
151
    (void)pabyCur;
83
151
    (void)nDataSize;
84
85
    /* -------------------------------------------------------------------- */
86
    /*  Apply constant min value.         */
87
    /* -------------------------------------------------------------------- */
88
52.9k
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
89
52.7k
        panData[i] = nMin;
90
91
151
    return (CE_None);
92
151
}
93
94
/************************************************************************/
95
/*                         AIGRolloverSignedAdd()                       */
96
/************************************************************************/
97
98
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
99
static GInt32 AIGRolloverSignedAdd(GInt32 a, GInt32 b)
100
456k
{
101
    // Not really portable as assumes complement to 2 representation
102
    // but AIG assumes typical unsigned rollover on signed
103
    // integer operations.
104
456k
    GInt32 res;
105
456k
    GUInt32 resUnsigned = (GUInt32)(a) + (GUInt32)(b);
106
456k
    memcpy(&res, &resUnsigned, sizeof(res));
107
456k
    return res;
108
456k
}
109
110
/************************************************************************/
111
/*                         AIGProcess32bitRawBlock()                    */
112
/*                                                                      */
113
/*      Process a block using ``20'' (thirty two bit) raw format.        */
114
/************************************************************************/
115
116
static CPLErr AIGProcessRaw32BitBlock(GByte *pabyCur, int nDataSize, int nMin,
117
                                      int nBlockXSize, int nBlockYSize,
118
                                      GInt32 *panData)
119
120
178
{
121
178
    int i;
122
123
178
    if (nDataSize < nBlockXSize * nBlockYSize * 4)
124
75
    {
125
75
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
126
75
        return CE_Failure;
127
75
    }
128
129
    /* -------------------------------------------------------------------- */
130
    /*      Collect raw data.                                               */
131
    /* -------------------------------------------------------------------- */
132
306
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
133
203
    {
134
203
        memcpy(panData + i, pabyCur, 4);
135
203
        panData[i] = CPL_MSBWORD32(panData[i]);
136
203
        panData[i] = AIGRolloverSignedAdd(panData[i], nMin);
137
203
        pabyCur += 4;
138
203
    }
139
140
103
    return (CE_None);
141
178
}
142
143
/************************************************************************/
144
/*                         AIGProcess16bitRawBlock()                    */
145
/*                                                                      */
146
/*      Process a block using ``10'' (sixteen bit) raw format.          */
147
/************************************************************************/
148
149
static CPLErr AIGProcessRaw16BitBlock(GByte *pabyCur, int nDataSize, int nMin,
150
                                      int nBlockXSize, int nBlockYSize,
151
                                      GInt32 *panData)
152
153
160
{
154
160
    int i;
155
156
160
    if (nDataSize < nBlockXSize * nBlockYSize * 2)
157
133
    {
158
133
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
159
133
        return CE_Failure;
160
133
    }
161
162
    /* -------------------------------------------------------------------- */
163
    /*      Collect raw data.                                               */
164
    /* -------------------------------------------------------------------- */
165
141
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
166
114
    {
167
114
        panData[i] = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
168
114
        pabyCur += 2;
169
114
    }
170
171
27
    return (CE_None);
172
160
}
173
174
/************************************************************************/
175
/*                         AIGProcess4BitRawBlock()                     */
176
/*                                                                      */
177
/*      Process a block using ``08'' raw format.                        */
178
/************************************************************************/
179
180
static CPLErr AIGProcessRaw4BitBlock(GByte *pabyCur, int nDataSize, int nMin,
181
                                     int nBlockXSize, int nBlockYSize,
182
                                     GInt32 *panData)
183
184
176
{
185
176
    int i;
186
187
176
    if (nDataSize < (nBlockXSize * nBlockYSize + 1) / 2)
188
86
    {
189
86
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
190
86
        return CE_Failure;
191
86
    }
192
193
    /* -------------------------------------------------------------------- */
194
    /*      Collect raw data.                                               */
195
    /* -------------------------------------------------------------------- */
196
272
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
197
182
    {
198
182
        if (i % 2 == 0)
199
92
            panData[i] = AIGRolloverSignedAdd((*(pabyCur)&0xf0) >> 4, nMin);
200
90
        else
201
90
            panData[i] = AIGRolloverSignedAdd(*(pabyCur++) & 0xf, nMin);
202
182
    }
203
204
90
    return (CE_None);
205
176
}
206
207
/************************************************************************/
208
/*                       AIGProcess1BitRawBlock()                       */
209
/*                                                                      */
210
/*      Process a block using ``0x01'' raw format.                      */
211
/************************************************************************/
212
213
static CPLErr AIGProcessRaw1BitBlock(GByte *pabyCur, int nDataSize, int nMin,
214
                                     int nBlockXSize, int nBlockYSize,
215
                                     GInt32 *panData)
216
217
286
{
218
286
    int i;
219
220
286
    if (nDataSize < (nBlockXSize * nBlockYSize + 7) / 8)
221
80
    {
222
80
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
223
80
        return CE_Failure;
224
80
    }
225
226
    /* -------------------------------------------------------------------- */
227
    /*      Collect raw data.                                               */
228
    /* -------------------------------------------------------------------- */
229
6.79k
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
230
6.59k
    {
231
6.59k
        if (pabyCur[i >> 3] & (0x80 >> (i & 0x7)))
232
2.22k
            panData[i] = AIGRolloverSignedAdd(1, nMin);
233
4.36k
        else
234
4.36k
            panData[i] = 0 + nMin;
235
6.59k
    }
236
237
206
    return (CE_None);
238
286
}
239
240
/************************************************************************/
241
/*                         AIGProcessRawBlock()                         */
242
/*                                                                      */
243
/*      Process a block using ``08'' raw format.                        */
244
/************************************************************************/
245
246
static CPLErr AIGProcessRawBlock(GByte *pabyCur, int nDataSize, int nMin,
247
                                 int nBlockXSize, int nBlockYSize,
248
                                 GInt32 *panData)
249
250
149
{
251
149
    int i;
252
253
149
    if (nDataSize < nBlockXSize * nBlockYSize)
254
96
    {
255
96
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
256
96
        return CE_Failure;
257
96
    }
258
259
    /* -------------------------------------------------------------------- */
260
    /*      Collect raw data.                                               */
261
    /* -------------------------------------------------------------------- */
262
345
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
263
292
    {
264
292
        panData[i] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
265
292
    }
266
267
53
    return (CE_None);
268
149
}
269
270
/************************************************************************/
271
/*                         AIGProcessFFBlock()                          */
272
/*                                                                      */
273
/*      Process a type 0xFF (CCITT RLE) compressed block.               */
274
/************************************************************************/
275
276
static CPLErr AIGProcessFFBlock(GByte *pabyCur, int nDataSize, int nMin,
277
                                int nBlockXSize, int nBlockYSize,
278
                                GInt32 *panData)
279
280
1.74k
{
281
    /* -------------------------------------------------------------------- */
282
    /*      Convert CCITT compress bitstream into 1bit raw data.            */
283
    /* -------------------------------------------------------------------- */
284
1.74k
    CPLErr eErr;
285
1.74k
    int i, nDstBytes = (nBlockXSize * nBlockYSize + 7) / 8;
286
1.74k
    unsigned char *pabyIntermediate;
287
288
1.74k
    pabyIntermediate = (unsigned char *)VSI_MALLOC_VERBOSE(nDstBytes);
289
1.74k
    if (pabyIntermediate == NULL)
290
0
    {
291
0
        return CE_Failure;
292
0
    }
293
294
1.74k
    eErr = DecompressCCITTRLETile(pabyCur, nDataSize, pabyIntermediate,
295
1.74k
                                  nDstBytes, nBlockXSize, nBlockYSize);
296
1.74k
    if (eErr != CE_None)
297
21
    {
298
21
        CPLFree(pabyIntermediate);
299
21
        return eErr;
300
21
    }
301
302
    /* -------------------------------------------------------------------- */
303
    /*      Convert the bit buffer into 32bit integers and account for      */
304
    /*      nMin.                                                           */
305
    /* -------------------------------------------------------------------- */
306
7.38M
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
307
7.38M
    {
308
7.38M
        if (pabyIntermediate[i >> 3] & (0x80 >> (i & 0x7)))
309
453k
            panData[i] = AIGRolloverSignedAdd(nMin, 1);
310
6.93M
        else
311
6.93M
            panData[i] = nMin;
312
7.38M
    }
313
314
1.72k
    CPLFree(pabyIntermediate);
315
316
1.72k
    return (CE_None);
317
1.74k
}
318
319
/************************************************************************/
320
/*                          AIGProcessBlock()                           */
321
/*                                                                      */
322
/*      Process a block using ``D7'', ``E0'' or ``DF'' compression.     */
323
/************************************************************************/
324
325
static CPLErr AIGProcessBlock(GByte *pabyCur, int nDataSize, int nMin,
326
                              int nMagic, int nBlockXSize, int nBlockYSize,
327
                              GInt32 *panData)
328
329
395
{
330
395
    int nTotPixels, nPixels;
331
395
    int i;
332
333
    /* ==================================================================== */
334
    /*     Process runs till we are done.                                  */
335
    /* ==================================================================== */
336
395
    nTotPixels = nBlockXSize * nBlockYSize;
337
395
    nPixels = 0;
338
339
2.59k
    while (nPixels < nTotPixels && nDataSize > 0)
340
2.22k
    {
341
2.22k
        int nMarker = *(pabyCur++);
342
343
2.22k
        nDataSize--;
344
345
        /* --------------------------------------------------------------------
346
         */
347
        /*      Repeat data - four byte data block (0xE0) */
348
        /* --------------------------------------------------------------------
349
         */
350
2.22k
        if (nMagic == 0xE0)
351
8
        {
352
8
            GInt32 nValue;
353
354
8
            if (nMarker + nPixels > nTotPixels)
355
1
            {
356
1
                CPLError(CE_Failure, CPLE_AppDefined,
357
1
                         "Run too long in AIGProcessBlock, needed %d values, "
358
1
                         "got %d.",
359
1
                         nTotPixels - nPixels, nMarker);
360
1
                return CE_Failure;
361
1
            }
362
363
7
            if (nDataSize < 4)
364
2
            {
365
2
                CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
366
2
                return CE_Failure;
367
2
            }
368
369
5
            nValue = 0;
370
5
            memcpy(&nValue, pabyCur, 4);
371
5
            pabyCur += 4;
372
5
            nDataSize -= 4;
373
374
5
            nValue = CPL_MSBWORD32(nValue);
375
5
            nValue = AIGRolloverSignedAdd(nValue, nMin);
376
271
            for (i = 0; i < nMarker; i++)
377
266
                panData[nPixels++] = nValue;
378
5
        }
379
380
        /* --------------------------------------------------------------------
381
         */
382
        /*      Repeat data - two byte data block (0xF0) */
383
        /* --------------------------------------------------------------------
384
         */
385
2.22k
        else if (nMagic == 0xF0)
386
316
        {
387
316
            GInt32 nValue;
388
389
316
            if (nMarker + nPixels > nTotPixels)
390
2
            {
391
2
                CPLError(CE_Failure, CPLE_AppDefined,
392
2
                         "Run too long in AIGProcessBlock, needed %d values, "
393
2
                         "got %d.",
394
2
                         nTotPixels - nPixels, nMarker);
395
2
                return CE_Failure;
396
2
            }
397
398
314
            if (nDataSize < 2)
399
3
            {
400
3
                CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
401
3
                return CE_Failure;
402
3
            }
403
404
311
            nValue = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
405
311
            pabyCur += 2;
406
311
            nDataSize -= 2;
407
408
1.43k
            for (i = 0; i < nMarker; i++)
409
1.11k
                panData[nPixels++] = nValue;
410
311
        }
411
412
        /* --------------------------------------------------------------------
413
         */
414
        /*      Repeat data - one byte data block (0xFC) */
415
        /* --------------------------------------------------------------------
416
         */
417
1.90k
        else if (nMagic == 0xFC || nMagic == 0xF8)
418
130
        {
419
130
            GInt32 nValue;
420
421
130
            if (nMarker + nPixels > nTotPixels)
422
6
            {
423
6
                CPLError(CE_Failure, CPLE_AppDefined,
424
6
                         "Run too long in AIGProcessBlock, needed %d values, "
425
6
                         "got %d.",
426
6
                         nTotPixels - nPixels, nMarker);
427
6
                return CE_Failure;
428
6
            }
429
430
124
            if (nDataSize < 1)
431
1
            {
432
1
                CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
433
1
                return CE_Failure;
434
1
            }
435
436
123
            nValue = AIGRolloverSignedAdd(*(pabyCur++), nMin);
437
123
            nDataSize--;
438
439
2.40k
            for (i = 0; i < nMarker; i++)
440
2.28k
                panData[nPixels++] = nValue;
441
123
        }
442
443
        /* --------------------------------------------------------------------
444
         */
445
        /*      Repeat data - no actual data, just assign minimum (0xDF) */
446
        /* --------------------------------------------------------------------
447
         */
448
1.77k
        else if (nMagic == 0xDF && nMarker < 128)
449
683
        {
450
683
            if (nMarker + nPixels > nTotPixels)
451
2
            {
452
2
                CPLError(CE_Failure, CPLE_AppDefined,
453
2
                         "Run too long in AIGProcessBlock, needed %d values, "
454
2
                         "got %d.",
455
2
                         nTotPixels - nPixels, nMarker);
456
2
                return CE_Failure;
457
2
            }
458
459
921
            for (i = 0; i < nMarker; i++)
460
240
                panData[nPixels++] = nMin;
461
681
        }
462
463
        /* --------------------------------------------------------------------
464
         */
465
        /*      Literal data (0xD7): 8bit values. */
466
        /* --------------------------------------------------------------------
467
         */
468
1.09k
        else if (nMagic == 0xD7 && nMarker < 128)
469
272
        {
470
272
            if (nMarker + nPixels > nTotPixels)
471
1
            {
472
1
                CPLError(CE_Failure, CPLE_AppDefined,
473
1
                         "Run too long in AIGProcessBlock, needed %d values, "
474
1
                         "got %d.",
475
1
                         nTotPixels - nPixels, nMarker);
476
1
                return CE_Failure;
477
1
            }
478
479
377
            while (nMarker > 0 && nDataSize > 0)
480
106
            {
481
106
                panData[nPixels++] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
482
106
                nMarker--;
483
106
                nDataSize--;
484
106
            }
485
271
        }
486
487
        /* --------------------------------------------------------------------
488
         */
489
        /*      Literal data (0xCF): 16 bit values. */
490
        /* --------------------------------------------------------------------
491
         */
492
820
        else if (nMagic == 0xCF && nMarker < 128)
493
90
        {
494
90
            GInt32 nValue;
495
496
90
            if (nMarker + nPixels > nTotPixels)
497
2
            {
498
2
                CPLError(CE_Failure, CPLE_AppDefined,
499
2
                         "Run too long in AIGProcessBlock, needed %d values, "
500
2
                         "got %d.",
501
2
                         nTotPixels - nPixels, nMarker);
502
2
                return CE_Failure;
503
2
            }
504
505
117
            while (nMarker > 0 && nDataSize >= 2)
506
29
            {
507
29
                nValue =
508
29
                    AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
509
29
                panData[nPixels++] = nValue;
510
29
                pabyCur += 2;
511
512
29
                nMarker--;
513
29
                nDataSize -= 2;
514
29
            }
515
88
        }
516
517
        /* --------------------------------------------------------------------
518
         */
519
        /*      Nodata repeat */
520
        /* --------------------------------------------------------------------
521
         */
522
730
        else if (nMarker > 128)
523
727
        {
524
727
            nMarker = 256 - nMarker;
525
526
727
            if (nMarker + nPixels > nTotPixels)
527
4
            {
528
4
                CPLError(CE_Failure, CPLE_AppDefined,
529
4
                         "Run too long in AIGProcessBlock, needed %d values, "
530
4
                         "got %d.",
531
4
                         nTotPixels - nPixels, nMarker);
532
4
                return CE_Failure;
533
4
            }
534
535
12.6k
            while (nMarker > 0)
536
11.9k
            {
537
11.9k
                panData[nPixels++] = ESRI_GRID_NO_DATA;
538
11.9k
                nMarker--;
539
11.9k
            }
540
723
        }
541
542
3
        else
543
3
        {
544
3
            return CE_Failure;
545
3
        }
546
2.22k
    }
547
548
368
    if (nPixels < nTotPixels || nDataSize < 0)
549
11
    {
550
11
        CPLError(CE_Failure, CPLE_AppDefined,
551
11
                 "Ran out of data processing block with nMagic=%d.", nMagic);
552
11
        return CE_Failure;
553
11
    }
554
555
357
    return CE_None;
556
368
}
557
558
/************************************************************************/
559
/*                            AIGReadBlock()                            */
560
/*                                                                      */
561
/*      Read a single block of integer grid data.                       */
562
/************************************************************************/
563
564
CPLErr AIGReadBlock(VSILFILE *fp, GUInt32 nBlockOffset, int nBlockSize,
565
                    int nBlockXSize, int nBlockYSize, GInt32 *panData,
566
                    int nCellType, int bCompressed)
567
568
5.24k
{
569
5.24k
    GByte *pabyRaw, *pabyCur;
570
5.24k
    CPLErr eErr;
571
5.24k
    int i, nMagic, nMinSize = 0, nDataSize;
572
5.24k
    GInt32 nMin = 0;
573
574
    /* -------------------------------------------------------------------- */
575
    /*      If the block has zero size it is all dummies.                   */
576
    /* -------------------------------------------------------------------- */
577
5.24k
    if (nBlockSize == 0)
578
1.63k
    {
579
3.34M
        for (i = 0; i < nBlockXSize * nBlockYSize; i++)
580
3.34M
            panData[i] = ESRI_GRID_NO_DATA;
581
582
1.63k
        return (CE_None);
583
1.63k
    }
584
585
    /* -------------------------------------------------------------------- */
586
    /*      Read the block into memory.                                     */
587
    /* -------------------------------------------------------------------- */
588
3.60k
    if (nBlockSize <= 0 || nBlockSize > 65535 * 2)
589
65
    {
590
65
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size : %d",
591
65
                 nBlockSize);
592
65
        return CE_Failure;
593
65
    }
594
595
3.54k
    pabyRaw = (GByte *)VSIMalloc(nBlockSize + 2);
596
3.54k
    if (pabyRaw == NULL)
597
0
    {
598
0
        CPLError(CE_Failure, CPLE_AppDefined,
599
0
                 "Cannot allocate memory for block");
600
0
        return CE_Failure;
601
0
    }
602
603
3.54k
    if (VSIFSeekL(fp, nBlockOffset, SEEK_SET) != 0 ||
604
3.54k
        VSIFReadL(pabyRaw, nBlockSize + 2, 1, fp) != 1)
605
134
    {
606
134
        memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
607
134
        CPLError(CE_Failure, CPLE_AppDefined,
608
134
                 "Read of %d bytes from offset %d for grid block failed.",
609
134
                 nBlockSize + 2, nBlockOffset);
610
134
        CPLFree(pabyRaw);
611
134
        return CE_Failure;
612
134
    }
613
614
    /* -------------------------------------------------------------------- */
615
    /*      Verify the block size.                                          */
616
    /* -------------------------------------------------------------------- */
617
3.41k
    if (nBlockSize != (pabyRaw[0] * 256 + pabyRaw[1]) * 2)
618
70
    {
619
70
        memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
620
70
        CPLError(CE_Failure, CPLE_AppDefined,
621
70
                 "Block is corrupt, block size was %d, but expected to be %d.",
622
70
                 (pabyRaw[0] * 256 + pabyRaw[1]) * 2, nBlockSize);
623
70
        CPLFree(pabyRaw);
624
70
        return CE_Failure;
625
70
    }
626
627
3.34k
    nDataSize = nBlockSize;
628
629
    /* -------------------------------------------------------------------- */
630
    /*      Handle float files and uncompressed integer files directly.     */
631
    /* -------------------------------------------------------------------- */
632
3.34k
    if (nCellType == AIG_CELLTYPE_FLOAT)
633
98
    {
634
98
        AIGProcessRaw32BitFloatBlock(pabyRaw + 2, nDataSize, 0, nBlockXSize,
635
98
                                     nBlockYSize, (float *)panData);
636
98
        CPLFree(pabyRaw);
637
638
98
        return CE_None;
639
98
    }
640
641
3.24k
    if (nCellType == AIG_CELLTYPE_INT && !bCompressed)
642
172
    {
643
172
        AIGProcessRaw32BitBlock(pabyRaw + 2, nDataSize, nMin, nBlockXSize,
644
172
                                nBlockYSize, panData);
645
172
        CPLFree(pabyRaw);
646
172
        return CE_None;
647
172
    }
648
649
    /* -------------------------------------------------------------------- */
650
    /*      Collect minimum value.                                          */
651
    /* -------------------------------------------------------------------- */
652
653
    /* The first 2 bytes that give the block size are not included in nDataSize
654
     */
655
    /* and have already been safely read */
656
3.07k
    pabyCur = pabyRaw + 2;
657
658
    /* Need at least 2 byte to read the nMinSize and the nMagic */
659
3.07k
    if (nDataSize < 2)
660
0
    {
661
0
        CPLError(CE_Failure, CPLE_AppDefined,
662
0
                 "Corrupt block. Need 2 bytes to read nMagic and nMinSize, "
663
0
                 "only %d available",
664
0
                 nDataSize);
665
0
        CPLFree(pabyRaw);
666
0
        return CE_Failure;
667
0
    }
668
3.07k
    nMagic = pabyCur[0];
669
3.07k
    nMinSize = pabyCur[1];
670
3.07k
    pabyCur += 2;
671
3.07k
    nDataSize -= 2;
672
673
    /* Need at least nMinSize bytes to read the nMin value */
674
3.07k
    if (nDataSize < nMinSize)
675
3
    {
676
3
        CPLError(CE_Failure, CPLE_AppDefined,
677
3
                 "Corrupt block. Need %d bytes to read nMin. Only %d available",
678
3
                 nMinSize, nDataSize);
679
3
        CPLFree(pabyRaw);
680
3
        return CE_Failure;
681
3
    }
682
683
3.06k
    if (nMinSize > 4)
684
1
    {
685
1
        memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
686
1
        CPLError(CE_Failure, CPLE_AppDefined,
687
1
                 "Corrupt 'minsize' of %d in block header.  Read aborted.",
688
1
                 nMinSize);
689
1
        CPLFree(pabyRaw);
690
1
        return CE_Failure;
691
1
    }
692
693
3.06k
    if (nMinSize == 4)
694
167
    {
695
167
        memcpy(&nMin, pabyCur, 4);
696
167
        nMin = CPL_MSBWORD32(nMin);
697
167
        pabyCur += 4;
698
167
    }
699
2.89k
    else
700
2.89k
    {
701
2.89k
        nMin = 0;
702
3.99k
        for (i = 0; i < nMinSize; i++)
703
1.10k
        {
704
1.10k
            nMin = nMin * 256 + *pabyCur;
705
1.10k
            pabyCur++;
706
1.10k
        }
707
708
        /* If nMinSize = 0, then we might have only 4 bytes in pabyRaw */
709
        /* don't try to read the 5th one then */
710
2.89k
        if (nMinSize != 0 && pabyRaw[4] > 127)
711
367
        {
712
367
            if (nMinSize == 2)
713
82
                nMin = nMin - 65536;
714
285
            else if (nMinSize == 1)
715
18
                nMin = nMin - 256;
716
267
            else if (nMinSize == 3)
717
267
                nMin = nMin - 256 * 256 * 256;
718
367
        }
719
2.89k
    }
720
721
3.06k
    nDataSize -= nMinSize;
722
723
    /* -------------------------------------------------------------------- */
724
    /*  Call an appropriate handler depending on magic code.    */
725
    /* -------------------------------------------------------------------- */
726
3.06k
    eErr = CE_None;
727
3.06k
    if (nMagic == 0x08)
728
149
    {
729
149
        AIGProcessRawBlock(pabyCur, nDataSize, nMin, nBlockXSize, nBlockYSize,
730
149
                           panData);
731
149
    }
732
2.91k
    else if (nMagic == 0x04)
733
176
    {
734
176
        AIGProcessRaw4BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
735
176
                               nBlockYSize, panData);
736
176
    }
737
2.74k
    else if (nMagic == 0x01)
738
286
    {
739
286
        AIGProcessRaw1BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
740
286
                               nBlockYSize, panData);
741
286
    }
742
2.45k
    else if (nMagic == 0x00)
743
151
    {
744
151
        AIGProcessIntConstBlock(pabyCur, nDataSize, nMin, nBlockXSize,
745
151
                                nBlockYSize, panData);
746
151
    }
747
2.30k
    else if (nMagic == 0x10)
748
160
    {
749
160
        AIGProcessRaw16BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
750
160
                                nBlockYSize, panData);
751
160
    }
752
2.14k
    else if (nMagic == 0x20)
753
6
    {
754
6
        AIGProcessRaw32BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
755
6
                                nBlockYSize, panData);
756
6
    }
757
2.13k
    else if (nMagic == 0xFF)
758
1.74k
    {
759
1.74k
        eErr = AIGProcessFFBlock(pabyCur, nDataSize, nMin, nBlockXSize,
760
1.74k
                                 nBlockYSize, panData);
761
1.74k
    }
762
395
    else
763
395
    {
764
395
        eErr = AIGProcessBlock(pabyCur, nDataSize, nMin, nMagic, nBlockXSize,
765
395
                               nBlockYSize, panData);
766
767
395
        if (eErr == CE_Failure)
768
38
        {
769
7.73M
            for (i = 0; i < nBlockXSize * nBlockYSize; i++)
770
7.73M
                panData[i] = ESRI_GRID_NO_DATA;
771
772
38
            CPLErrorOnce(CE_Warning, CPLE_AppDefined,
773
38
                         "Unsupported Arc/Info Binary Grid tile of type 0x%X"
774
38
                         " encountered.\n"
775
38
                         "This and subsequent unsupported tile types set to"
776
38
                         " no data value.\n",
777
38
                         nMagic);
778
38
        }
779
395
    }
780
781
3.06k
    CPLFree(pabyRaw);
782
783
3.06k
    return eErr;
784
3.06k
}
785
786
/************************************************************************/
787
/*                           AIGReadHeader()                            */
788
/*                                                                      */
789
/*      Read the hdr.adf file, and populate the given info structure    */
790
/*      appropriately.                                                  */
791
/************************************************************************/
792
793
CPLErr AIGReadHeader(const char *pszCoverName, AIGInfo_t *psInfo)
794
795
8.45k
{
796
8.45k
    char *pszHDRFilename;
797
8.45k
    VSILFILE *fp;
798
8.45k
    GByte abyData[308];
799
8.45k
    const size_t nHDRFilenameLen = strlen(pszCoverName) + 30;
800
801
    /* -------------------------------------------------------------------- */
802
    /*      Open the file hdr.adf file.                                     */
803
    /* -------------------------------------------------------------------- */
804
8.45k
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
805
8.45k
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/hdr.adf", pszCoverName);
806
807
8.45k
    fp = AIGLLOpen(pszHDRFilename, "rb");
808
809
8.45k
    if (fp == NULL)
810
10
    {
811
10
        CPLError(CE_Failure, CPLE_OpenFailed,
812
10
                 "Failed to open grid header file:\n%s\n", pszHDRFilename);
813
814
10
        CPLFree(pszHDRFilename);
815
10
        return (CE_Failure);
816
10
    }
817
818
8.44k
    CPLFree(pszHDRFilename);
819
820
    /* -------------------------------------------------------------------- */
821
    /*      Read the whole file (we expect it to always be 308 bytes        */
822
    /*      long.                                                           */
823
    /* -------------------------------------------------------------------- */
824
825
8.44k
    if (VSIFReadL(abyData, 1, 308, fp) != 308)
826
36
    {
827
36
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
828
36
        return (CE_Failure);
829
36
    }
830
831
8.40k
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
832
833
    /* -------------------------------------------------------------------- */
834
    /*      Read the block size information.                                */
835
    /* -------------------------------------------------------------------- */
836
8.40k
    memcpy(&(psInfo->nCellType), abyData + 16, 4);
837
8.40k
    memcpy(&(psInfo->bCompressed), abyData + 20, 4);
838
8.40k
    memcpy(&(psInfo->nBlocksPerRow), abyData + 288, 4);
839
8.40k
    memcpy(&(psInfo->nBlocksPerColumn), abyData + 292, 4);
840
8.40k
    memcpy(&(psInfo->nBlockXSize), abyData + 296, 4);
841
8.40k
    memcpy(&(psInfo->nBlockYSize), abyData + 304, 4);
842
8.40k
    memcpy(&(psInfo->dfCellSizeX), abyData + 256, 8);
843
8.40k
    memcpy(&(psInfo->dfCellSizeY), abyData + 264, 8);
844
845
8.40k
#ifdef CPL_LSB
846
8.40k
    psInfo->nCellType = CPL_SWAP32(psInfo->nCellType);
847
8.40k
    psInfo->bCompressed = CPL_SWAP32(psInfo->bCompressed);
848
8.40k
    psInfo->nBlocksPerRow = CPL_SWAP32(psInfo->nBlocksPerRow);
849
8.40k
    psInfo->nBlocksPerColumn = CPL_SWAP32(psInfo->nBlocksPerColumn);
850
8.40k
    psInfo->nBlockXSize = CPL_SWAP32(psInfo->nBlockXSize);
851
8.40k
    psInfo->nBlockYSize = CPL_SWAP32(psInfo->nBlockYSize);
852
8.40k
    CPL_SWAPDOUBLE(&(psInfo->dfCellSizeX));
853
8.40k
    CPL_SWAPDOUBLE(&(psInfo->dfCellSizeY));
854
8.40k
#endif
855
856
8.40k
    psInfo->bCompressed = !psInfo->bCompressed;
857
858
8.40k
    return (CE_None);
859
8.44k
}
860
861
/************************************************************************/
862
/*                         AIGReadBlockIndex()                          */
863
/*                                                                      */
864
/*      Read the w001001x.adf file, and populate the given info         */
865
/*      structure with the block offsets, and sizes.                    */
866
/************************************************************************/
867
868
CPLErr AIGReadBlockIndex(AIGInfo_t *psInfo, AIGTileInfo *psTInfo,
869
                         const char *pszBasename)
870
871
996
{
872
996
    char *pszHDRFilename;
873
996
    VSILFILE *fp;
874
996
    int i;
875
996
    GUInt32 nValue, nLength;
876
996
    GUInt32 *panIndex;
877
996
    GByte abyHeader[8];
878
996
    const size_t nHDRFilenameLen = strlen(psInfo->pszCoverName) + 40;
879
880
    /* -------------------------------------------------------------------- */
881
    /*      Open the file hdr.adf file.                                     */
882
    /* -------------------------------------------------------------------- */
883
996
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
884
996
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/%sx.adf",
885
996
             psInfo->pszCoverName, pszBasename);
886
887
996
    fp = AIGLLOpen(pszHDRFilename, "rb");
888
889
996
    if (fp == NULL)
890
478
    {
891
478
        CPLError(CE_Failure, CPLE_OpenFailed,
892
478
                 "Failed to open grid block index file:\n%s\n", pszHDRFilename);
893
894
478
        CPLFree(pszHDRFilename);
895
478
        return (CE_Failure);
896
478
    }
897
898
518
    CPLFree(pszHDRFilename);
899
900
    /* -------------------------------------------------------------------- */
901
    /*      Verify the magic number.  This is often corrupted by CR/LF      */
902
    /*      translation.                                                    */
903
    /* -------------------------------------------------------------------- */
904
518
    if (VSIFReadL(abyHeader, 1, 8, fp) != 8)
905
2
    {
906
2
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
907
2
        return CE_Failure;
908
2
    }
909
516
    if (abyHeader[3] == 0x0D && abyHeader[4] == 0x0A)
910
0
    {
911
0
        CPLError(CE_Failure, CPLE_AppDefined,
912
0
                 "w001001x.adf file header has been corrupted by unix to dos "
913
0
                 "text conversion.");
914
0
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
915
0
        return CE_Failure;
916
0
    }
917
918
516
    if (abyHeader[0] != 0x00 || abyHeader[1] != 0x00 || abyHeader[2] != 0x27 ||
919
516
        abyHeader[3] != 0x0A || abyHeader[4] != 0xFF || abyHeader[5] != 0xFF)
920
7
    {
921
7
        CPLError(CE_Failure, CPLE_AppDefined,
922
7
                 "w001001x.adf file header magic number is corrupt.");
923
7
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
924
7
        return CE_Failure;
925
7
    }
926
927
    /* -------------------------------------------------------------------- */
928
    /*      Get the file length (in 2 byte shorts)                          */
929
    /* -------------------------------------------------------------------- */
930
509
    if (VSIFSeekL(fp, 24, SEEK_SET) != 0 || VSIFReadL(&nValue, 1, 4, fp) != 4)
931
2
    {
932
2
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
933
2
        return CE_Failure;
934
2
    }
935
936
507
    nValue = CPL_MSBWORD32(nValue);
937
507
    if (nValue > INT_MAX)
938
6
    {
939
6
        CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
940
6
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
941
6
        return CE_Failure;
942
6
    }
943
501
    nLength = nValue * 2;
944
501
    if (nLength <= 100)
945
5
    {
946
5
        CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
947
5
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
948
5
        return CE_Failure;
949
5
    }
950
951
    /* -------------------------------------------------------------------- */
952
    /*      Allocate buffer, and read the file (from beyond the header)     */
953
    /*      into the buffer.                                                */
954
    /* -------------------------------------------------------------------- */
955
496
    psTInfo->nBlocks = (nLength - 100) / 8;
956
496
    if (psTInfo->nBlocks >= 1000000)
957
33
    {
958
        // Avoid excessive memory consumption.
959
33
        vsi_l_offset nFileSize;
960
33
        VSIFSeekL(fp, 0, SEEK_END);
961
33
        nFileSize = VSIFTellL(fp);
962
33
        if (nFileSize < 100 ||
963
33
            (vsi_l_offset)psTInfo->nBlocks > (nFileSize - 100) / 8)
964
33
        {
965
33
            CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
966
33
            return CE_Failure;
967
33
        }
968
33
    }
969
463
    panIndex = (GUInt32 *)VSI_MALLOC2_VERBOSE(psTInfo->nBlocks, 8);
970
463
    if (panIndex == NULL)
971
0
    {
972
0
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
973
0
        return CE_Failure;
974
0
    }
975
463
    if (VSIFSeekL(fp, 100, SEEK_SET) != 0 ||
976
463
        (int)VSIFReadL(panIndex, 8, psTInfo->nBlocks, fp) != psTInfo->nBlocks)
977
30
    {
978
30
        CPLError(CE_Failure, CPLE_AppDefined,
979
30
                 "AIGReadBlockIndex: Cannot read block info");
980
30
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
981
30
        CPLFree(panIndex);
982
30
        return CE_Failure;
983
30
    }
984
985
433
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
986
987
    /* -------------------------------------------------------------------- */
988
    /*  Allocate AIGInfo block info arrays.       */
989
    /* -------------------------------------------------------------------- */
990
433
    psTInfo->panBlockOffset =
991
433
        (GUInt32 *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
992
433
    psTInfo->panBlockSize = (int *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
993
433
    if (psTInfo->panBlockOffset == NULL || psTInfo->panBlockSize == NULL)
994
0
    {
995
0
        CPLFree(psTInfo->panBlockOffset);
996
0
        CPLFree(psTInfo->panBlockSize);
997
0
        psTInfo->panBlockOffset = NULL;
998
0
        psTInfo->panBlockSize = NULL;
999
0
        CPLFree(panIndex);
1000
0
        return CE_Failure;
1001
0
    }
1002
1003
    /* -------------------------------------------------------------------- */
1004
    /*      Populate the block information.                                 */
1005
    /* -------------------------------------------------------------------- */
1006
37.2k
    for (i = 0; i < psTInfo->nBlocks; i++)
1007
36.8k
    {
1008
36.8k
        GUInt32 nVal;
1009
1010
36.8k
        nVal = CPL_MSBWORD32(panIndex[i * 2]);
1011
36.8k
        if (nVal >= INT_MAX)
1012
3
        {
1013
3
            CPLError(CE_Failure, CPLE_AppDefined,
1014
3
                     "AIGReadBlockIndex: Bad offset for block %d", i);
1015
3
            CPLFree(psTInfo->panBlockOffset);
1016
3
            CPLFree(psTInfo->panBlockSize);
1017
3
            psTInfo->panBlockOffset = NULL;
1018
3
            psTInfo->panBlockSize = NULL;
1019
3
            CPLFree(panIndex);
1020
3
            return CE_Failure;
1021
3
        }
1022
36.8k
        psTInfo->panBlockOffset[i] = nVal * 2;
1023
1024
36.8k
        nVal = CPL_MSBWORD32(panIndex[i * 2 + 1]);
1025
36.8k
        if (nVal >= INT_MAX / 2)
1026
11
        {
1027
11
            CPLError(CE_Failure, CPLE_AppDefined,
1028
11
                     "AIGReadBlockIndex: Bad size for block %d", i);
1029
11
            CPLFree(psTInfo->panBlockOffset);
1030
11
            CPLFree(psTInfo->panBlockSize);
1031
11
            psTInfo->panBlockOffset = NULL;
1032
11
            psTInfo->panBlockSize = NULL;
1033
11
            CPLFree(panIndex);
1034
11
            return CE_Failure;
1035
11
        }
1036
36.8k
        psTInfo->panBlockSize[i] = nVal * 2;
1037
36.8k
    }
1038
1039
419
    CPLFree(panIndex);
1040
1041
419
    return (CE_None);
1042
433
}
1043
1044
/************************************************************************/
1045
/*                           AIGReadBounds()                            */
1046
/*                                                                      */
1047
/*      Read the dblbnd.adf file for the georeferenced bounds.          */
1048
/************************************************************************/
1049
1050
CPLErr AIGReadBounds(const char *pszCoverName, AIGInfo_t *psInfo)
1051
1052
8.40k
{
1053
8.40k
    char *pszHDRFilename;
1054
8.40k
    VSILFILE *fp;
1055
8.40k
    double adfBound[4];
1056
8.40k
    const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
1057
1058
    /* -------------------------------------------------------------------- */
1059
    /*      Open the file dblbnd.adf file.                                  */
1060
    /* -------------------------------------------------------------------- */
1061
8.40k
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
1062
8.40k
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/dblbnd.adf", pszCoverName);
1063
1064
8.40k
    fp = AIGLLOpen(pszHDRFilename, "rb");
1065
1066
8.40k
    if (fp == NULL)
1067
37
    {
1068
37
        CPLError(CE_Failure, CPLE_OpenFailed,
1069
37
                 "Failed to open grid bounds file:\n%s\n", pszHDRFilename);
1070
1071
37
        CPLFree(pszHDRFilename);
1072
37
        return (CE_Failure);
1073
37
    }
1074
1075
8.37k
    CPLFree(pszHDRFilename);
1076
1077
    /* -------------------------------------------------------------------- */
1078
    /*      Get the contents - four doubles.                                */
1079
    /* -------------------------------------------------------------------- */
1080
8.37k
    if (VSIFReadL(adfBound, 1, 32, fp) != 32)
1081
7
    {
1082
7
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1083
7
        return CE_Failure;
1084
7
    }
1085
1086
8.36k
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1087
1088
8.36k
#ifdef CPL_LSB
1089
8.36k
    CPL_SWAPDOUBLE(adfBound + 0);
1090
8.36k
    CPL_SWAPDOUBLE(adfBound + 1);
1091
8.36k
    CPL_SWAPDOUBLE(adfBound + 2);
1092
8.36k
    CPL_SWAPDOUBLE(adfBound + 3);
1093
8.36k
#endif
1094
1095
8.36k
    psInfo->dfLLX = adfBound[0];
1096
8.36k
    psInfo->dfLLY = adfBound[1];
1097
8.36k
    psInfo->dfURX = adfBound[2];
1098
8.36k
    psInfo->dfURY = adfBound[3];
1099
1100
8.36k
    return (CE_None);
1101
8.37k
}
1102
1103
/************************************************************************/
1104
/*                         AIGReadStatistics()                          */
1105
/*                                                                      */
1106
/*      Read the sta.adf file for the layer statistics.                 */
1107
/************************************************************************/
1108
1109
CPLErr AIGReadStatistics(const char *pszCoverName, AIGInfo_t *psInfo)
1110
1111
8.10k
{
1112
8.10k
    char *pszHDRFilename;
1113
8.10k
    VSILFILE *fp;
1114
8.10k
    double adfStats[4];
1115
8.10k
    const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
1116
8.10k
    size_t nRead;
1117
1118
8.10k
    psInfo->dfMin = 0.0;
1119
8.10k
    psInfo->dfMax = 0.0;
1120
8.10k
    psInfo->dfMean = 0.0;
1121
8.10k
    psInfo->dfStdDev = -1.0;
1122
1123
    /* -------------------------------------------------------------------- */
1124
    /*      Open the file sta.adf file.                                     */
1125
    /* -------------------------------------------------------------------- */
1126
8.10k
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
1127
8.10k
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/sta.adf", pszCoverName);
1128
1129
8.10k
    fp = AIGLLOpen(pszHDRFilename, "rb");
1130
1131
8.10k
    if (fp == NULL)
1132
3
    {
1133
3
        CPLError(CE_Failure, CPLE_OpenFailed,
1134
3
                 "Failed to open grid statistics file:\n%s\n", pszHDRFilename);
1135
1136
3
        CPLFree(pszHDRFilename);
1137
3
        return (CE_Failure);
1138
3
    }
1139
1140
    /* -------------------------------------------------------------------- */
1141
    /*      Get the contents - 3 or 4 doubles.                              */
1142
    /* -------------------------------------------------------------------- */
1143
8.09k
    nRead = VSIFReadL(adfStats, 1, 32, fp);
1144
1145
8.09k
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1146
1147
8.09k
    if (nRead == 32)
1148
8.09k
    {
1149
8.09k
#ifdef CPL_LSB
1150
8.09k
        CPL_SWAPDOUBLE(adfStats + 0);
1151
8.09k
        CPL_SWAPDOUBLE(adfStats + 1);
1152
8.09k
        CPL_SWAPDOUBLE(adfStats + 2);
1153
8.09k
        CPL_SWAPDOUBLE(adfStats + 3);
1154
8.09k
#endif
1155
1156
8.09k
        psInfo->dfMin = adfStats[0];
1157
8.09k
        psInfo->dfMax = adfStats[1];
1158
8.09k
        psInfo->dfMean = adfStats[2];
1159
8.09k
        psInfo->dfStdDev = adfStats[3];
1160
8.09k
    }
1161
3
    else if (nRead == 24)
1162
2
    {
1163
        /* See dataset at https://trac.osgeo.org/gdal/ticket/6633 */
1164
        /* In that case, we have only min, max and mean, in LSB ordering */
1165
2
        CPL_LSBPTR64(adfStats + 0);
1166
2
        CPL_LSBPTR64(adfStats + 1);
1167
2
        CPL_LSBPTR64(adfStats + 2);
1168
1169
2
        psInfo->dfMin = adfStats[0];
1170
2
        psInfo->dfMax = adfStats[1];
1171
2
        psInfo->dfMean = adfStats[2];
1172
2
    }
1173
1
    else
1174
1
    {
1175
1
        CPLError(CE_Failure, CPLE_AppDefined, "Wrong content for %s",
1176
1
                 pszHDRFilename);
1177
1
        CPLFree(pszHDRFilename);
1178
1
        return CE_Failure;
1179
1
    }
1180
1181
8.09k
    CPLFree(pszHDRFilename);
1182
8.09k
    return CE_None;
1183
8.09k
}