Coverage Report

Created: 2026-08-11 08:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/aigrid/gridlib.c
Line
Count
Source
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.2k
{
21
25.2k
}
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
61
{
35
61
    int i;
36
37
61
    (void)nMin;
38
61
    if (nDataSize < (GIntBig)nBlockXSize * nBlockYSize * 4)
39
61
    {
40
61
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
41
61
        return CE_Failure;
42
61
    }
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
61
}
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
95
{
80
95
    int i;
81
82
95
    (void)pabyCur;
83
95
    (void)nDataSize;
84
85
    /* -------------------------------------------------------------------- */
86
    /*  Apply constant min value.         */
87
    /* -------------------------------------------------------------------- */
88
166k
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
89
166k
        panData[i] = nMin;
90
91
95
    return (CE_None);
92
95
}
93
94
/************************************************************************/
95
/*                        AIGRolloverSignedAdd()                        */
96
/************************************************************************/
97
98
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
99
static GInt32 AIGRolloverSignedAdd(GInt32 a, GInt32 b)
100
213k
{
101
    // Not really portable as assumes complement to 2 representation
102
    // but AIG assumes typical unsigned rollover on signed
103
    // integer operations.
104
213k
    GInt32 res;
105
213k
    GUInt32 resUnsigned = (GUInt32)(a) + (GUInt32)(b);
106
213k
    memcpy(&res, &resUnsigned, sizeof(res));
107
213k
    return res;
108
213k
}
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
187
{
121
187
    int i;
122
123
187
    if (nDataSize < (GIntBig)nBlockXSize * nBlockYSize * 4)
124
103
    {
125
103
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
126
103
        return CE_Failure;
127
103
    }
128
129
    /* -------------------------------------------------------------------- */
130
    /*      Collect raw data.                                               */
131
    /* -------------------------------------------------------------------- */
132
252
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
133
168
    {
134
168
        memcpy(panData + i, pabyCur, 4);
135
168
        panData[i] = CPL_MSBWORD32(panData[i]);
136
168
        panData[i] = AIGRolloverSignedAdd(panData[i], nMin);
137
168
        pabyCur += 4;
138
168
    }
139
140
84
    return (CE_None);
141
187
}
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
253
{
154
253
    int i;
155
156
253
    if (nDataSize < (GIntBig)nBlockXSize * nBlockYSize * 2)
157
146
    {
158
146
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
159
146
        return CE_Failure;
160
146
    }
161
162
    /* -------------------------------------------------------------------- */
163
    /*      Collect raw data.                                               */
164
    /* -------------------------------------------------------------------- */
165
341
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
166
234
    {
167
234
        panData[i] = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
168
234
        pabyCur += 2;
169
234
    }
170
171
107
    return (CE_None);
172
253
}
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
149
{
185
149
    int i;
186
187
149
    if (nDataSize < ((GIntBig)nBlockXSize * nBlockYSize + 1) / 2)
188
78
    {
189
78
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
190
78
        return CE_Failure;
191
78
    }
192
193
    /* -------------------------------------------------------------------- */
194
    /*      Collect raw data.                                               */
195
    /* -------------------------------------------------------------------- */
196
1.00k
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
197
930
    {
198
930
        if (i % 2 == 0)
199
494
            panData[i] = AIGRolloverSignedAdd((*(pabyCur) & 0xf0) >> 4, nMin);
200
436
        else
201
436
            panData[i] = AIGRolloverSignedAdd(*(pabyCur++) & 0xf, nMin);
202
930
    }
203
204
71
    return (CE_None);
205
149
}
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
296
{
218
296
    int i;
219
220
296
    if (nDataSize < ((GIntBig)nBlockXSize * nBlockYSize + 7) / 8)
221
150
    {
222
150
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
223
150
        return CE_Failure;
224
150
    }
225
226
    /* -------------------------------------------------------------------- */
227
    /*      Collect raw data.                                               */
228
    /* -------------------------------------------------------------------- */
229
7.55k
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
230
7.40k
    {
231
7.40k
        if (pabyCur[i >> 3] & (0x80 >> (i & 0x7)))
232
2.38k
            panData[i] = AIGRolloverSignedAdd(1, nMin);
233
5.01k
        else
234
5.01k
            panData[i] = 0 + nMin;
235
7.40k
    }
236
237
146
    return (CE_None);
238
296
}
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
34
{
251
34
    int i;
252
253
34
    if (nDataSize < (GIntBig)nBlockXSize * nBlockYSize)
254
24
    {
255
24
        CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
256
24
        return CE_Failure;
257
24
    }
258
259
    /* -------------------------------------------------------------------- */
260
    /*      Collect raw data.                                               */
261
    /* -------------------------------------------------------------------- */
262
34
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
263
24
    {
264
24
        panData[i] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
265
24
    }
266
267
10
    return (CE_None);
268
34
}
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.13k
{
281
    /* -------------------------------------------------------------------- */
282
    /*      Convert CCITT compress bitstream into 1bit raw data.            */
283
    /* -------------------------------------------------------------------- */
284
1.13k
    CPLErr eErr;
285
1.13k
    int i, nDstBytes = (nBlockXSize * nBlockYSize + 7) / 8;
286
1.13k
    unsigned char *pabyIntermediate;
287
288
1.13k
    pabyIntermediate = (unsigned char *)VSI_MALLOC_VERBOSE(nDstBytes);
289
1.13k
    if (pabyIntermediate == NULL)
290
0
    {
291
0
        return CE_Failure;
292
0
    }
293
294
1.13k
    eErr = DecompressCCITTRLETile(pabyCur, nDataSize, pabyIntermediate,
295
1.13k
                                  nDstBytes, nBlockXSize, nBlockYSize);
296
1.13k
    if (eErr != CE_None)
297
10
    {
298
10
        CPLFree(pabyIntermediate);
299
10
        return eErr;
300
10
    }
301
302
    /* -------------------------------------------------------------------- */
303
    /*      Convert the bit buffer into 32bit integers and account for      */
304
    /*      nMin.                                                           */
305
    /* -------------------------------------------------------------------- */
306
1.12M
    for (i = 0; i < nBlockXSize * nBlockYSize; i++)
307
1.12M
    {
308
1.12M
        if (pabyIntermediate[i >> 3] & (0x80 >> (i & 0x7)))
309
209k
            panData[i] = AIGRolloverSignedAdd(nMin, 1);
310
913k
        else
311
913k
            panData[i] = nMin;
312
1.12M
    }
313
314
1.12k
    CPLFree(pabyIntermediate);
315
316
1.12k
    return (CE_None);
317
1.13k
}
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
321
{
330
321
    int nTotPixels, nPixels;
331
321
    int i;
332
333
    /* ==================================================================== */
334
    /*     Process runs till we are done.                                  */
335
    /* ==================================================================== */
336
321
    nTotPixels = nBlockXSize * nBlockYSize;
337
321
    nPixels = 0;
338
339
2.17k
    while (nPixels < nTotPixels && nDataSize > 0)
340
1.87k
    {
341
1.87k
        int nMarker = *(pabyCur++);
342
343
1.87k
        nDataSize--;
344
345
        /* --------------------------------------------------------------------
346
         */
347
        /*      Repeat data - four byte data block (0xE0) */
348
        /* --------------------------------------------------------------------
349
         */
350
1.87k
        if (nMagic == 0xE0)
351
0
        {
352
0
            GInt32 nValue;
353
354
0
            if (nMarker + nPixels > nTotPixels)
355
0
            {
356
0
                CPLError(CE_Failure, CPLE_AppDefined,
357
0
                         "Run too long in AIGProcessBlock, needed %d values, "
358
0
                         "got %d.",
359
0
                         nTotPixels - nPixels, nMarker);
360
0
                return CE_Failure;
361
0
            }
362
363
0
            if (nDataSize < 4)
364
0
            {
365
0
                CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
366
0
                return CE_Failure;
367
0
            }
368
369
0
            nValue = 0;
370
0
            memcpy(&nValue, pabyCur, 4);
371
0
            pabyCur += 4;
372
0
            nDataSize -= 4;
373
374
0
            nValue = CPL_MSBWORD32(nValue);
375
0
            nValue = AIGRolloverSignedAdd(nValue, nMin);
376
0
            for (i = 0; i < nMarker; i++)
377
0
                panData[nPixels++] = nValue;
378
0
        }
379
380
        /* --------------------------------------------------------------------
381
         */
382
        /*      Repeat data - two byte data block (0xF0) */
383
        /* --------------------------------------------------------------------
384
         */
385
1.87k
        else if (nMagic == 0xF0)
386
89
        {
387
89
            GInt32 nValue;
388
389
89
            if (nMarker + nPixels > nTotPixels)
390
3
            {
391
3
                CPLError(CE_Failure, CPLE_AppDefined,
392
3
                         "Run too long in AIGProcessBlock, needed %d values, "
393
3
                         "got %d.",
394
3
                         nTotPixels - nPixels, nMarker);
395
3
                return CE_Failure;
396
3
            }
397
398
86
            if (nDataSize < 2)
399
1
            {
400
1
                CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
401
1
                return CE_Failure;
402
1
            }
403
404
85
            nValue = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
405
85
            pabyCur += 2;
406
85
            nDataSize -= 2;
407
408
527
            for (i = 0; i < nMarker; i++)
409
442
                panData[nPixels++] = nValue;
410
85
        }
411
412
        /* --------------------------------------------------------------------
413
         */
414
        /*      Repeat data - one byte data block (0xFC) */
415
        /* --------------------------------------------------------------------
416
         */
417
1.78k
        else if (nMagic == 0xFC || nMagic == 0xF8)
418
73
        {
419
73
            GInt32 nValue;
420
421
73
            if (nMarker + nPixels > nTotPixels)
422
2
            {
423
2
                CPLError(CE_Failure, CPLE_AppDefined,
424
2
                         "Run too long in AIGProcessBlock, needed %d values, "
425
2
                         "got %d.",
426
2
                         nTotPixels - nPixels, nMarker);
427
2
                return CE_Failure;
428
2
            }
429
430
71
            if (nDataSize < 1)
431
0
            {
432
0
                CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
433
0
                return CE_Failure;
434
0
            }
435
436
71
            nValue = AIGRolloverSignedAdd(*(pabyCur++), nMin);
437
71
            nDataSize--;
438
439
1.42k
            for (i = 0; i < nMarker; i++)
440
1.35k
                panData[nPixels++] = nValue;
441
71
        }
442
443
        /* --------------------------------------------------------------------
444
         */
445
        /*      Repeat data - no actual data, just assign minimum (0xDF) */
446
        /* --------------------------------------------------------------------
447
         */
448
1.71k
        else if (nMagic == 0xDF && nMarker < 128)
449
24
        {
450
24
            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
860
            for (i = 0; i < nMarker; i++)
460
838
                panData[nPixels++] = nMin;
461
22
        }
462
463
        /* --------------------------------------------------------------------
464
         */
465
        /*      Literal data (0xD7): 8bit values. */
466
        /* --------------------------------------------------------------------
467
         */
468
1.69k
        else if (nMagic == 0xD7 && nMarker < 128)
469
709
        {
470
709
            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
932
            while (nMarker > 0 && nDataSize > 0)
480
224
            {
481
224
                panData[nPixels++] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
482
224
                nMarker--;
483
224
                nDataSize--;
484
224
            }
485
708
        }
486
487
        /* --------------------------------------------------------------------
488
         */
489
        /*      Literal data (0xCF): 16 bit values. */
490
        /* --------------------------------------------------------------------
491
         */
492
981
        else if (nMagic == 0xCF && nMarker < 128)
493
313
        {
494
313
            GInt32 nValue;
495
496
313
            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
369
            while (nMarker > 0 && nDataSize >= 2)
506
58
            {
507
58
                nValue =
508
58
                    AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
509
58
                panData[nPixels++] = nValue;
510
58
                pabyCur += 2;
511
512
58
                nMarker--;
513
58
                nDataSize -= 2;
514
58
            }
515
311
        }
516
517
        /* --------------------------------------------------------------------
518
         */
519
        /*      Nodata repeat */
520
        /* --------------------------------------------------------------------
521
         */
522
668
        else if (nMarker > 128)
523
664
        {
524
664
            nMarker = 256 - nMarker;
525
526
664
            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
8.87k
            while (nMarker > 0)
536
8.21k
            {
537
8.21k
                panData[nPixels++] = ESRI_GRID_NO_DATA;
538
8.21k
                nMarker--;
539
8.21k
            }
540
660
        }
541
542
4
        else
543
4
        {
544
4
            return CE_Failure;
545
4
        }
546
1.87k
    }
547
548
302
    if (nPixels < nTotPixels || nDataSize < 0)
549
14
    {
550
14
        CPLError(CE_Failure, CPLE_AppDefined,
551
14
                 "Ran out of data processing block with nMagic=%d.", nMagic);
552
14
        return CE_Failure;
553
14
    }
554
555
288
    return CE_None;
556
302
}
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
3.84k
{
569
3.84k
    GByte *pabyRaw, *pabyCur;
570
3.84k
    CPLErr eErr;
571
3.84k
    int i, nMagic, nMinSize = 0, nDataSize;
572
3.84k
    GInt32 nMin = 0;
573
574
    /* -------------------------------------------------------------------- */
575
    /*      If the block has zero size it is all dummies.                   */
576
    /* -------------------------------------------------------------------- */
577
3.84k
    if (nBlockSize == 0)
578
1.08k
    {
579
5.28M
        for (i = 0; i < nBlockXSize * nBlockYSize; i++)
580
5.28M
            panData[i] = ESRI_GRID_NO_DATA;
581
582
1.08k
        return (CE_None);
583
1.08k
    }
584
585
    /* -------------------------------------------------------------------- */
586
    /*      Read the block into memory.                                     */
587
    /* -------------------------------------------------------------------- */
588
2.75k
    if (nBlockSize <= 0 || nBlockSize > 65535 * 2)
589
55
    {
590
55
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size : %d",
591
55
                 nBlockSize);
592
55
        return CE_Failure;
593
55
    }
594
595
2.70k
    pabyRaw = (GByte *)VSIMalloc(nBlockSize + 2);
596
2.70k
    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
2.70k
    if (VSIFSeekL(fp, nBlockOffset, SEEK_SET) != 0 ||
604
2.70k
        VSIFReadL(pabyRaw, nBlockSize + 2, 1, fp) != 1)
605
101
    {
606
101
        memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
607
101
        CPLError(CE_Failure, CPLE_AppDefined,
608
101
                 "Read of %d bytes from offset %d for grid block failed.",
609
101
                 nBlockSize + 2, nBlockOffset);
610
101
        CPLFree(pabyRaw);
611
101
        return CE_Failure;
612
101
    }
613
614
    /* -------------------------------------------------------------------- */
615
    /*      Verify the block size.                                          */
616
    /* -------------------------------------------------------------------- */
617
2.60k
    if (nBlockSize != (pabyRaw[0] * 256 + pabyRaw[1]) * 2)
618
63
    {
619
63
        memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
620
63
        CPLError(CE_Failure, CPLE_AppDefined,
621
63
                 "Block is corrupt, block size was %d, but expected to be %d.",
622
63
                 (pabyRaw[0] * 256 + pabyRaw[1]) * 2, nBlockSize);
623
63
        CPLFree(pabyRaw);
624
63
        return CE_Failure;
625
63
    }
626
627
2.53k
    nDataSize = nBlockSize;
628
629
    /* -------------------------------------------------------------------- */
630
    /*      Handle float files and uncompressed integer files directly.     */
631
    /* -------------------------------------------------------------------- */
632
2.53k
    if (nCellType == AIG_CELLTYPE_FLOAT)
633
61
    {
634
61
        AIGProcessRaw32BitFloatBlock(pabyRaw + 2, nDataSize, 0, nBlockXSize,
635
61
                                     nBlockYSize, (float *)panData);
636
61
        CPLFree(pabyRaw);
637
638
61
        return CE_None;
639
61
    }
640
641
2.47k
    if (nCellType == AIG_CELLTYPE_INT && !bCompressed)
642
167
    {
643
167
        AIGProcessRaw32BitBlock(pabyRaw + 2, nDataSize, nMin, nBlockXSize,
644
167
                                nBlockYSize, panData);
645
167
        CPLFree(pabyRaw);
646
167
        return CE_None;
647
167
    }
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
2.30k
    pabyCur = pabyRaw + 2;
657
658
    /* Need at least 2 byte to read the nMinSize and the nMagic */
659
2.30k
    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
2.30k
    nMagic = pabyCur[0];
669
2.30k
    nMinSize = pabyCur[1];
670
2.30k
    pabyCur += 2;
671
2.30k
    nDataSize -= 2;
672
673
    /* Need at least nMinSize bytes to read the nMin value */
674
2.30k
    if (nDataSize < nMinSize)
675
1
    {
676
1
        CPLError(CE_Failure, CPLE_AppDefined,
677
1
                 "Corrupt block. Need %d bytes to read nMin. Only %d available",
678
1
                 nMinSize, nDataSize);
679
1
        CPLFree(pabyRaw);
680
1
        return CE_Failure;
681
1
    }
682
683
2.30k
    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
2.30k
    if (nMinSize == 4)
694
152
    {
695
152
        memcpy(&nMin, pabyCur, 4);
696
152
        nMin = CPL_MSBWORD32(nMin);
697
152
        pabyCur += 4;
698
152
    }
699
2.15k
    else
700
2.15k
    {
701
2.15k
        nMin = 0;
702
2.94k
        for (i = 0; i < nMinSize; i++)
703
789
        {
704
789
            nMin = nMin * 256 + *pabyCur;
705
789
            pabyCur++;
706
789
        }
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.15k
        if (nMinSize != 0 && pabyRaw[4] > 127)
711
271
        {
712
271
            if (nMinSize == 2)
713
199
                nMin = nMin - 65536;
714
72
            else if (nMinSize == 1)
715
6
                nMin = nMin - 256;
716
66
            else if (nMinSize == 3)
717
66
                nMin = nMin - 256 * 256 * 256;
718
271
        }
719
2.15k
    }
720
721
2.30k
    nDataSize -= nMinSize;
722
723
    /* -------------------------------------------------------------------- */
724
    /*  Call an appropriate handler depending on magic code.    */
725
    /* -------------------------------------------------------------------- */
726
2.30k
    eErr = CE_None;
727
2.30k
    if (nMagic == 0x08)
728
34
    {
729
34
        AIGProcessRawBlock(pabyCur, nDataSize, nMin, nBlockXSize, nBlockYSize,
730
34
                           panData);
731
34
    }
732
2.27k
    else if (nMagic == 0x04)
733
149
    {
734
149
        AIGProcessRaw4BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
735
149
                               nBlockYSize, panData);
736
149
    }
737
2.12k
    else if (nMagic == 0x01)
738
296
    {
739
296
        AIGProcessRaw1BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
740
296
                               nBlockYSize, panData);
741
296
    }
742
1.82k
    else if (nMagic == 0x00)
743
95
    {
744
95
        AIGProcessIntConstBlock(pabyCur, nDataSize, nMin, nBlockXSize,
745
95
                                nBlockYSize, panData);
746
95
    }
747
1.73k
    else if (nMagic == 0x10)
748
253
    {
749
253
        AIGProcessRaw16BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
750
253
                                nBlockYSize, panData);
751
253
    }
752
1.48k
    else if (nMagic == 0x20)
753
20
    {
754
20
        AIGProcessRaw32BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
755
20
                                nBlockYSize, panData);
756
20
    }
757
1.46k
    else if (nMagic == 0xFF)
758
1.13k
    {
759
1.13k
        eErr = AIGProcessFFBlock(pabyCur, nDataSize, nMin, nBlockXSize,
760
1.13k
                                 nBlockYSize, panData);
761
1.13k
    }
762
321
    else
763
321
    {
764
321
        eErr = AIGProcessBlock(pabyCur, nDataSize, nMin, nMagic, nBlockXSize,
765
321
                               nBlockYSize, panData);
766
767
321
        if (eErr == CE_Failure)
768
33
        {
769
3.47M
            for (i = 0; i < nBlockXSize * nBlockYSize; i++)
770
3.47M
                panData[i] = ESRI_GRID_NO_DATA;
771
772
33
            CPLErrorOnce(CE_Warning, CPLE_AppDefined,
773
33
                         "Unsupported Arc/Info Binary Grid tile of type 0x%X"
774
33
                         " encountered.\n"
775
33
                         "This and subsequent unsupported tile types set to"
776
33
                         " no data value.\n",
777
33
                         nMagic);
778
33
        }
779
321
    }
780
781
2.30k
    CPLFree(pabyRaw);
782
783
2.30k
    return eErr;
784
2.30k
}
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.39k
{
796
8.39k
    char *pszHDRFilename;
797
8.39k
    VSILFILE *fp;
798
8.39k
    GByte abyData[308];
799
8.39k
    const size_t nHDRFilenameLen = strlen(pszCoverName) + 30;
800
801
    /* -------------------------------------------------------------------- */
802
    /*      Open the file hdr.adf file.                                     */
803
    /* -------------------------------------------------------------------- */
804
8.39k
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
805
8.39k
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/hdr.adf", pszCoverName);
806
807
8.39k
    fp = AIGLLOpen(pszHDRFilename, "rb");
808
809
8.39k
    if (fp == NULL)
810
24
    {
811
24
        CPLError(CE_Failure, CPLE_OpenFailed,
812
24
                 "Failed to open grid header file:\n%s\n", pszHDRFilename);
813
814
24
        CPLFree(pszHDRFilename);
815
24
        return (CE_Failure);
816
24
    }
817
818
8.36k
    CPLFree(pszHDRFilename);
819
820
    /* -------------------------------------------------------------------- */
821
    /*      Read the whole file (we expect it to always be 308 bytes        */
822
    /*      long.                                                           */
823
    /* -------------------------------------------------------------------- */
824
825
8.36k
    if (VSIFReadL(abyData, 1, 308, fp) != 308)
826
25
    {
827
25
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
828
25
        return (CE_Failure);
829
25
    }
830
831
8.34k
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
832
833
    /* -------------------------------------------------------------------- */
834
    /*      Read the block size information.                                */
835
    /* -------------------------------------------------------------------- */
836
8.34k
    memcpy(&(psInfo->nCellType), abyData + 16, 4);
837
8.34k
    memcpy(&(psInfo->bCompressed), abyData + 20, 4);
838
8.34k
    memcpy(&(psInfo->nBlocksPerRow), abyData + 288, 4);
839
8.34k
    memcpy(&(psInfo->nBlocksPerColumn), abyData + 292, 4);
840
8.34k
    memcpy(&(psInfo->nBlockXSize), abyData + 296, 4);
841
8.34k
    memcpy(&(psInfo->nBlockYSize), abyData + 304, 4);
842
8.34k
    memcpy(&(psInfo->dfCellSizeX), abyData + 256, 8);
843
8.34k
    memcpy(&(psInfo->dfCellSizeY), abyData + 264, 8);
844
845
8.34k
#ifdef CPL_LSB
846
8.34k
    psInfo->nCellType = CPL_SWAP32(psInfo->nCellType);
847
8.34k
    psInfo->bCompressed = CPL_SWAP32(psInfo->bCompressed);
848
8.34k
    psInfo->nBlocksPerRow = CPL_SWAP32(psInfo->nBlocksPerRow);
849
8.34k
    psInfo->nBlocksPerColumn = CPL_SWAP32(psInfo->nBlocksPerColumn);
850
8.34k
    psInfo->nBlockXSize = CPL_SWAP32(psInfo->nBlockXSize);
851
8.34k
    psInfo->nBlockYSize = CPL_SWAP32(psInfo->nBlockYSize);
852
8.34k
    CPL_SWAPDOUBLE(&(psInfo->dfCellSizeX));
853
8.34k
    CPL_SWAPDOUBLE(&(psInfo->dfCellSizeY));
854
8.34k
#endif
855
856
8.34k
    psInfo->bCompressed = !psInfo->bCompressed;
857
858
8.34k
    return (CE_None);
859
8.36k
}
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
822
{
872
822
    char *pszHDRFilename;
873
822
    VSILFILE *fp;
874
822
    int i;
875
822
    GUInt32 nValue, nLength;
876
822
    GUInt32 *panIndex;
877
822
    GByte abyHeader[8];
878
822
    const size_t nHDRFilenameLen = strlen(psInfo->pszCoverName) + 40;
879
880
    /* -------------------------------------------------------------------- */
881
    /*      Open the file hdr.adf file.                                     */
882
    /* -------------------------------------------------------------------- */
883
822
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
884
822
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/%sx.adf",
885
822
             psInfo->pszCoverName, pszBasename);
886
887
822
    fp = AIGLLOpen(pszHDRFilename, "rb");
888
889
822
    if (fp == NULL)
890
333
    {
891
333
        CPLError(CE_Failure, CPLE_OpenFailed,
892
333
                 "Failed to open grid block index file:\n%s\n", pszHDRFilename);
893
894
333
        CPLFree(pszHDRFilename);
895
333
        return (CE_Failure);
896
333
    }
897
898
489
    CPLFree(pszHDRFilename);
899
900
    /* -------------------------------------------------------------------- */
901
    /*      Verify the magic number.  This is often corrupted by CR/LF      */
902
    /*      translation.                                                    */
903
    /* -------------------------------------------------------------------- */
904
489
    if (VSIFReadL(abyHeader, 1, 8, fp) != 8)
905
1
    {
906
1
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
907
1
        return CE_Failure;
908
1
    }
909
488
    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
488
    if (abyHeader[0] != 0x00 || abyHeader[1] != 0x00 || abyHeader[2] != 0x27 ||
919
485
        abyHeader[3] != 0x0A || abyHeader[4] != 0xFF || abyHeader[5] != 0xFF)
920
8
    {
921
8
        CPLError(CE_Failure, CPLE_AppDefined,
922
8
                 "w001001x.adf file header magic number is corrupt.");
923
8
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
924
8
        return CE_Failure;
925
8
    }
926
927
    /* -------------------------------------------------------------------- */
928
    /*      Get the file length (in 2 byte shorts)                          */
929
    /* -------------------------------------------------------------------- */
930
480
    if (VSIFSeekL(fp, 24, SEEK_SET) != 0 || VSIFReadL(&nValue, 1, 4, fp) != 4)
931
0
    {
932
0
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
933
0
        return CE_Failure;
934
0
    }
935
936
480
    nValue = CPL_MSBWORD32(nValue);
937
480
    if (nValue > INT_MAX)
938
17
    {
939
17
        CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
940
17
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
941
17
        return CE_Failure;
942
17
    }
943
463
    nLength = nValue * 2;
944
463
    if (nLength <= 100)
945
3
    {
946
3
        CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
947
3
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
948
3
        return CE_Failure;
949
3
    }
950
951
    /* -------------------------------------------------------------------- */
952
    /*      Allocate buffer, and read the file (from beyond the header)     */
953
    /*      into the buffer.                                                */
954
    /* -------------------------------------------------------------------- */
955
460
    psTInfo->nBlocks = (nLength - 100) / 8;
956
460
    if (psTInfo->nBlocks >= 1000000)
957
35
    {
958
        // Avoid excessive memory consumption.
959
35
        vsi_l_offset nFileSize;
960
35
        VSIFSeekL(fp, 0, SEEK_END);
961
35
        nFileSize = VSIFTellL(fp);
962
35
        if (nFileSize < 100 ||
963
30
            (vsi_l_offset)psTInfo->nBlocks > (nFileSize - 100) / 8)
964
35
        {
965
35
            CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
966
35
            return CE_Failure;
967
35
        }
968
35
    }
969
425
    panIndex = (GUInt32 *)VSI_MALLOC2_VERBOSE(psTInfo->nBlocks, 8);
970
425
    if (panIndex == NULL)
971
4
    {
972
4
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
973
4
        return CE_Failure;
974
4
    }
975
421
    if (VSIFSeekL(fp, 100, SEEK_SET) != 0 ||
976
421
        (int)VSIFReadL(panIndex, 8, psTInfo->nBlocks, fp) != psTInfo->nBlocks)
977
33
    {
978
33
        CPLError(CE_Failure, CPLE_AppDefined,
979
33
                 "AIGReadBlockIndex: Cannot read block info");
980
33
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
981
33
        CPLFree(panIndex);
982
33
        return CE_Failure;
983
33
    }
984
985
388
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
986
987
    /* -------------------------------------------------------------------- */
988
    /*  Allocate AIGInfo block info arrays.       */
989
    /* -------------------------------------------------------------------- */
990
388
    psTInfo->panBlockOffset =
991
388
        (GUInt32 *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
992
388
    psTInfo->panBlockSize = (int *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
993
388
    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
36.7k
    for (i = 0; i < psTInfo->nBlocks; i++)
1007
36.4k
    {
1008
36.4k
        GUInt32 nVal;
1009
1010
36.4k
        nVal = CPL_MSBWORD32(panIndex[i * 2]);
1011
36.4k
        if (nVal >= INT_MAX)
1012
4
        {
1013
4
            CPLError(CE_Failure, CPLE_AppDefined,
1014
4
                     "AIGReadBlockIndex: Bad offset for block %d", i);
1015
4
            CPLFree(psTInfo->panBlockOffset);
1016
4
            CPLFree(psTInfo->panBlockSize);
1017
4
            psTInfo->panBlockOffset = NULL;
1018
4
            psTInfo->panBlockSize = NULL;
1019
4
            CPLFree(panIndex);
1020
4
            return CE_Failure;
1021
4
        }
1022
36.4k
        psTInfo->panBlockOffset[i] = nVal * 2;
1023
1024
36.4k
        nVal = CPL_MSBWORD32(panIndex[i * 2 + 1]);
1025
36.4k
        if (nVal >= INT_MAX / 2)
1026
21
        {
1027
21
            CPLError(CE_Failure, CPLE_AppDefined,
1028
21
                     "AIGReadBlockIndex: Bad size for block %d", i);
1029
21
            CPLFree(psTInfo->panBlockOffset);
1030
21
            CPLFree(psTInfo->panBlockSize);
1031
21
            psTInfo->panBlockOffset = NULL;
1032
21
            psTInfo->panBlockSize = NULL;
1033
21
            CPLFree(panIndex);
1034
21
            return CE_Failure;
1035
21
        }
1036
36.3k
        psTInfo->panBlockSize[i] = nVal * 2;
1037
36.3k
    }
1038
1039
363
    CPLFree(panIndex);
1040
1041
363
    return (CE_None);
1042
388
}
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.34k
{
1053
8.34k
    char *pszHDRFilename;
1054
8.34k
    VSILFILE *fp;
1055
8.34k
    double adfBound[4];
1056
8.34k
    const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
1057
1058
    /* -------------------------------------------------------------------- */
1059
    /*      Open the file dblbnd.adf file.                                  */
1060
    /* -------------------------------------------------------------------- */
1061
8.34k
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
1062
8.34k
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/dblbnd.adf", pszCoverName);
1063
1064
8.34k
    fp = AIGLLOpen(pszHDRFilename, "rb");
1065
1066
8.34k
    if (fp == NULL)
1067
32
    {
1068
32
        CPLError(CE_Failure, CPLE_OpenFailed,
1069
32
                 "Failed to open grid bounds file:\n%s\n", pszHDRFilename);
1070
1071
32
        CPLFree(pszHDRFilename);
1072
32
        return (CE_Failure);
1073
32
    }
1074
1075
8.30k
    CPLFree(pszHDRFilename);
1076
1077
    /* -------------------------------------------------------------------- */
1078
    /*      Get the contents - four doubles.                                */
1079
    /* -------------------------------------------------------------------- */
1080
8.30k
    if (VSIFReadL(adfBound, 1, 32, fp) != 32)
1081
1
    {
1082
1
        CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1083
1
        return CE_Failure;
1084
1
    }
1085
1086
8.30k
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1087
1088
8.30k
#ifdef CPL_LSB
1089
8.30k
    CPL_SWAPDOUBLE(adfBound + 0);
1090
8.30k
    CPL_SWAPDOUBLE(adfBound + 1);
1091
8.30k
    CPL_SWAPDOUBLE(adfBound + 2);
1092
8.30k
    CPL_SWAPDOUBLE(adfBound + 3);
1093
8.30k
#endif
1094
1095
8.30k
    psInfo->dfLLX = adfBound[0];
1096
8.30k
    psInfo->dfLLY = adfBound[1];
1097
8.30k
    psInfo->dfURX = adfBound[2];
1098
8.30k
    psInfo->dfURY = adfBound[3];
1099
1100
8.30k
    return (CE_None);
1101
8.30k
}
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.04k
{
1112
8.04k
    char *pszHDRFilename;
1113
8.04k
    VSILFILE *fp;
1114
8.04k
    double adfStats[4];
1115
8.04k
    const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
1116
8.04k
    size_t nRead;
1117
1118
8.04k
    psInfo->dfMin = 0.0;
1119
8.04k
    psInfo->dfMax = 0.0;
1120
8.04k
    psInfo->dfMean = 0.0;
1121
8.04k
    psInfo->dfStdDev = -1.0;
1122
1123
    /* -------------------------------------------------------------------- */
1124
    /*      Open the file sta.adf file.                                     */
1125
    /* -------------------------------------------------------------------- */
1126
8.04k
    pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
1127
8.04k
    snprintf(pszHDRFilename, nHDRFilenameLen, "%s/sta.adf", pszCoverName);
1128
1129
8.04k
    fp = AIGLLOpen(pszHDRFilename, "rb");
1130
1131
8.04k
    if (fp == NULL)
1132
10
    {
1133
10
        CPLError(CE_Failure, CPLE_OpenFailed,
1134
10
                 "Failed to open grid statistics file:\n%s\n", pszHDRFilename);
1135
1136
10
        CPLFree(pszHDRFilename);
1137
10
        return (CE_Failure);
1138
10
    }
1139
1140
    /* -------------------------------------------------------------------- */
1141
    /*      Get the contents - 3 or 4 doubles.                              */
1142
    /* -------------------------------------------------------------------- */
1143
8.03k
    nRead = VSIFReadL(adfStats, 1, 32, fp);
1144
1145
8.03k
    CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
1146
1147
8.03k
    if (nRead == 32)
1148
8.03k
    {
1149
8.03k
#ifdef CPL_LSB
1150
8.03k
        CPL_SWAPDOUBLE(adfStats + 0);
1151
8.03k
        CPL_SWAPDOUBLE(adfStats + 1);
1152
8.03k
        CPL_SWAPDOUBLE(adfStats + 2);
1153
8.03k
        CPL_SWAPDOUBLE(adfStats + 3);
1154
8.03k
#endif
1155
1156
8.03k
        psInfo->dfMin = adfStats[0];
1157
8.03k
        psInfo->dfMax = adfStats[1];
1158
8.03k
        psInfo->dfMean = adfStats[2];
1159
8.03k
        psInfo->dfStdDev = adfStats[3];
1160
8.03k
    }
1161
5
    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
3
    else
1174
3
    {
1175
3
        CPLError(CE_Failure, CPLE_AppDefined, "Wrong content for %s",
1176
3
                 pszHDRFilename);
1177
3
        CPLFree(pszHDRFilename);
1178
3
        return CE_Failure;
1179
3
    }
1180
1181
8.03k
    CPLFree(pszHDRFilename);
1182
8.03k
    return CE_None;
1183
8.03k
}