Coverage Report

Created: 2026-02-14 09:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/hfa/hfaband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  Erdas Imagine (.img) Translator
4
 * Purpose:  Implementation of the HFABand, for accessing one Eimg_Layer.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1999, Intergraph Corporation
9
 * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "hfa_p.h"
16
17
#include <cerrno>
18
#include <climits>
19
#include <cstddef>
20
#include <cstdio>
21
#include <cstring>
22
#include <algorithm>
23
24
#include "cpl_conv.h"
25
#include "cpl_error.h"
26
#include "cpl_string.h"
27
#include "cpl_vsi.h"
28
#include "hfa.h"
29
#include "gdal_priv.h"
30
31
/************************************************************************/
32
/*                              HFABand()                               */
33
/************************************************************************/
34
35
HFABand::HFABand(HFAInfo_t *psInfoIn, HFAEntry *poNodeIn)
36
40.7k
    : nBlocks(0), panBlockStart(nullptr), panBlockSize(nullptr),
37
40.7k
      panBlockFlag(nullptr), nBlockStart(0), nBlockSize(0), nLayerStackCount(0),
38
40.7k
      nLayerStackIndex(0), nPCTColors(-1), padfPCTBins(nullptr),
39
40.7k
      psInfo(psInfoIn), fpExternal(nullptr),
40
40.7k
      eDataType(static_cast<EPTType>(poNodeIn->GetIntField("pixelType"))),
41
40.7k
      poNode(poNodeIn), nBlockXSize(poNodeIn->GetIntField("blockWidth")),
42
40.7k
      nBlockYSize(poNodeIn->GetIntField("blockHeight")),
43
40.7k
      nWidth(poNodeIn->GetIntField("width")),
44
40.7k
      nHeight(poNodeIn->GetIntField("height")), nBlocksPerRow(0),
45
40.7k
      nBlocksPerColumn(0), bNoDataSet(false), dfNoData(0.0),
46
40.7k
      bOverviewsPending(true), nOverviews(0), papoOverviews(nullptr)
47
40.7k
{
48
40.7k
    const int nDataType = poNodeIn->GetIntField("pixelType");
49
50
40.7k
    apadfPCT[0] = nullptr;
51
40.7k
    apadfPCT[1] = nullptr;
52
40.7k
    apadfPCT[2] = nullptr;
53
40.7k
    apadfPCT[3] = nullptr;
54
55
40.7k
    if (nWidth <= 0 || nHeight <= 0 || nBlockXSize <= 0 || nBlockYSize <= 0)
56
305
    {
57
305
        nWidth = 0;
58
305
        nHeight = 0;
59
305
        CPLError(CE_Failure, CPLE_AppDefined,
60
305
                 "HFABand::HFABand : (nWidth <= 0 || nHeight <= 0 || "
61
305
                 "nBlockXSize <= 0 || nBlockYSize <= 0)");
62
305
        return;
63
305
    }
64
40.4k
    if (nDataType < EPT_MIN || nDataType > EPT_MAX)
65
13
    {
66
13
        nWidth = 0;
67
13
        nHeight = 0;
68
13
        CPLError(CE_Failure, CPLE_AppDefined,
69
13
                 "HFABand::HFABand : nDataType=%d unhandled", nDataType);
70
13
        return;
71
13
    }
72
73
    // TODO(schwehr): Move to initializer list.
74
40.4k
    nBlocksPerRow = DIV_ROUND_UP(nWidth, nBlockXSize);
75
40.4k
    nBlocksPerColumn = DIV_ROUND_UP(nHeight, nBlockYSize);
76
77
40.4k
    if (nBlocksPerRow > INT_MAX / nBlocksPerColumn)
78
16
    {
79
16
        nWidth = 0;
80
16
        nHeight = 0;
81
16
        CPLError(CE_Failure, CPLE_AppDefined,
82
16
                 "HFABand::HFABand : too big dimensions / block size");
83
16
        return;
84
16
    }
85
40.4k
    nBlocks = nBlocksPerRow * nBlocksPerColumn;
86
87
    // Check for nodata.  This is really an RDO (ESRI Raster Data Objects?),
88
    // not used by Imagine itself.
89
40.4k
    HFAEntry *poNDNode = poNode->GetNamedChild("Eimg_NonInitializedValue");
90
91
40.4k
    if (poNDNode != nullptr)
92
173
    {
93
173
        bNoDataSet = true;
94
173
        dfNoData = poNDNode->GetDoubleField("valueBD");
95
173
    }
96
40.4k
}
97
98
/************************************************************************/
99
/*                              ~HFABand()                              */
100
/************************************************************************/
101
102
HFABand::~HFABand()
103
104
40.7k
{
105
47.3k
    for (int iOverview = 0; iOverview < nOverviews; iOverview++)
106
6.57k
        delete papoOverviews[iOverview];
107
108
40.7k
    if (nOverviews > 0)
109
178
        CPLFree(papoOverviews);
110
111
40.7k
    CPLFree(panBlockStart);
112
40.7k
    CPLFree(panBlockSize);
113
40.7k
    CPLFree(panBlockFlag);
114
115
40.7k
    CPLFree(apadfPCT[0]);
116
40.7k
    CPLFree(apadfPCT[1]);
117
40.7k
    CPLFree(apadfPCT[2]);
118
40.7k
    CPLFree(apadfPCT[3]);
119
40.7k
    CPLFree(padfPCTBins);
120
121
40.7k
    if (fpExternal != nullptr)
122
14
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpExternal));
123
40.7k
}
124
125
/************************************************************************/
126
/*                           LoadOverviews()                            */
127
/************************************************************************/
128
129
CPLErr HFABand::LoadOverviews()
130
131
14.1k
{
132
14.1k
    if (!bOverviewsPending)
133
6.57k
        return CE_None;
134
135
7.59k
    bOverviewsPending = false;
136
137
    // Does this band have overviews?  Try to find them.
138
7.59k
    HFAEntry *poRRDNames = poNode->GetNamedChild("RRDNamesList");
139
140
7.59k
    if (poRRDNames != nullptr)
141
462
    {
142
        // Limit to 1000 to avoid infinite loop as in
143
        // https://oss-fuzz.com/v2/testcase-detail/6206784937132032
144
98.4k
        for (int iName = 0; iName < 1000; iName++)
145
98.4k
        {
146
98.4k
            char szField[128] = {};
147
98.4k
            snprintf(szField, sizeof(szField), "nameList[%d].string", iName);
148
149
98.4k
            CPLErr eErr = CE_None;
150
98.4k
            const char *pszName = poRRDNames->GetStringField(szField, &eErr);
151
98.4k
            if (pszName == nullptr || eErr != CE_None)
152
459
                break;
153
154
97.9k
            char *pszFilename = CPLStrdup(pszName);
155
97.9k
            char *pszEnd = strstr(pszFilename, "(:");
156
97.9k
            if (pszEnd == nullptr)
157
69.4k
            {
158
69.4k
                CPLFree(pszFilename);
159
69.4k
                continue;
160
69.4k
            }
161
162
28.4k
            pszEnd[0] = '\0';
163
164
28.4k
            char *pszJustFilename = CPLStrdup(CPLGetFilename(pszFilename));
165
28.4k
            HFAInfo_t *psHFA = HFAGetDependent(psInfo, pszJustFilename);
166
28.4k
            CPLFree(pszJustFilename);
167
168
            // Try finding the dependent file as this file with the
169
            // extension .rrd.  This is intended to address problems
170
            // with users changing the names of their files.
171
28.4k
            if (psHFA == nullptr)
172
19.5k
            {
173
19.5k
                char *pszBasename =
174
19.5k
                    CPLStrdup(CPLGetBasenameSafe(psInfo->pszFilename).c_str());
175
176
19.5k
                pszJustFilename = CPLStrdup(
177
19.5k
                    CPLFormFilenameSafe(nullptr, pszBasename, "rrd").c_str());
178
19.5k
                CPLDebug("HFA",
179
19.5k
                         "Failed to find overview file with "
180
19.5k
                         "expected name, try %s instead.",
181
19.5k
                         pszJustFilename);
182
19.5k
                psHFA = HFAGetDependent(psInfo, pszJustFilename);
183
19.5k
                CPLFree(pszJustFilename);
184
19.5k
                CPLFree(pszBasename);
185
19.5k
            }
186
187
28.4k
            if (psHFA == nullptr)
188
19.5k
            {
189
19.5k
                CPLFree(pszFilename);
190
19.5k
                continue;
191
19.5k
            }
192
193
8.92k
            char *pszPath = pszEnd + 2;
194
8.92k
            {
195
8.92k
                const int nPathLen = static_cast<int>(strlen(pszPath));
196
8.92k
                if (pszPath[nPathLen - 1] == ')')
197
81
                    pszPath[nPathLen - 1] = '\0';
198
8.92k
            }
199
200
71.4k
            for (int i = 0; pszPath[i] != '\0'; i++)
201
62.5k
            {
202
62.5k
                if (pszPath[i] == ':')
203
2.12k
                    pszPath[i] = '.';
204
62.5k
            }
205
206
8.92k
            HFAEntry *poOvEntry = psHFA->poRoot->GetNamedChild(pszPath);
207
8.92k
            CPLFree(pszFilename);
208
209
8.92k
            if (poOvEntry == nullptr)
210
2.41k
                continue;
211
212
            // We have an overview node.  Instantiate a HFABand from it, and
213
            // add to the list.
214
6.50k
            papoOverviews = static_cast<HFABand **>(
215
6.50k
                CPLRealloc(papoOverviews, sizeof(void *) * ++nOverviews));
216
6.50k
            papoOverviews[nOverviews - 1] = new HFABand(psHFA, poOvEntry);
217
6.50k
            if (papoOverviews[nOverviews - 1]->nWidth == 0)
218
2
            {
219
2
                nWidth = 0;
220
2
                nHeight = 0;
221
2
                delete papoOverviews[nOverviews - 1];
222
2
                papoOverviews[nOverviews - 1] = nullptr;
223
2
                return CE_None;
224
2
            }
225
6.50k
        }
226
462
    }
227
228
    // If there are no overviews mentioned in this file, probe for
229
    // an .rrd file anyways.
230
7.59k
    HFAEntry *poBandProxyNode = poNode;
231
7.59k
    HFAInfo_t *psOvHFA = psInfo;
232
233
7.59k
    if (nOverviews == 0 &&
234
7.48k
        EQUAL(CPLGetExtensionSafe(psInfo->pszFilename).c_str(), "aux"))
235
0
    {
236
0
        const CPLString osRRDFilename =
237
0
            CPLResetExtensionSafe(psInfo->pszFilename, "rrd");
238
0
        const CPLString osFullRRD =
239
0
            CPLFormFilenameSafe(psInfo->pszPath, osRRDFilename, nullptr);
240
0
        VSIStatBufL sStatBuf;
241
242
0
        if (VSIStatL(osFullRRD, &sStatBuf) == 0)
243
0
        {
244
0
            psOvHFA = HFAGetDependent(psInfo, osRRDFilename);
245
0
            if (psOvHFA)
246
0
                poBandProxyNode =
247
0
                    psOvHFA->poRoot->GetNamedChild(poNode->GetName());
248
0
            else
249
0
                psOvHFA = psInfo;
250
0
        }
251
0
    }
252
253
    // If there are no named overviews, try looking for unnamed
254
    // overviews within the same layer, as occurs in floodplain.img
255
    // for instance, or in the not-referenced rrd mentioned in #3463.
256
7.59k
    if (nOverviews == 0 && poBandProxyNode != nullptr)
257
7.48k
    {
258
7.48k
        for (HFAEntry *poChild = poBandProxyNode->GetChild();
259
40.4k
             poChild != nullptr; poChild = poChild->GetNext())
260
33.0k
        {
261
33.0k
            if (EQUAL(poChild->GetType(), "Eimg_Layer_SubSample"))
262
73
            {
263
73
                papoOverviews = static_cast<HFABand **>(
264
73
                    CPLRealloc(papoOverviews, sizeof(void *) * ++nOverviews));
265
73
                papoOverviews[nOverviews - 1] = new HFABand(psOvHFA, poChild);
266
73
                if (papoOverviews[nOverviews - 1]->nWidth == 0)
267
8
                {
268
8
                    nWidth = 0;
269
8
                    nHeight = 0;
270
8
                    delete papoOverviews[nOverviews - 1];
271
8
                    papoOverviews[nOverviews - 1] = nullptr;
272
8
                    return CE_None;
273
8
                }
274
73
            }
275
33.0k
        }
276
277
        // TODO(schwehr): Can this use std::sort?
278
        // Bubble sort into biggest to smallest order.
279
7.54k
        for (int i1 = 0; i1 < nOverviews; i1++)
280
65
        {
281
65
            for (int i2 = 0; i2 < nOverviews - 1; i2++)
282
0
            {
283
0
                if (papoOverviews[i2]->nWidth < papoOverviews[i2 + 1]->nWidth)
284
0
                {
285
                    // TODO(schwehr): Use std::swap.
286
0
                    HFABand *poTemp = papoOverviews[i2 + 1];
287
0
                    papoOverviews[i2 + 1] = papoOverviews[i2];
288
0
                    papoOverviews[i2] = poTemp;
289
0
                }
290
0
            }
291
65
        }
292
7.47k
    }
293
7.58k
    return CE_None;
294
7.59k
}
295
296
/************************************************************************/
297
/*                           LoadBlockInfo()                            */
298
/************************************************************************/
299
300
CPLErr HFABand::LoadBlockInfo()
301
302
32.4k
{
303
32.4k
    if (panBlockFlag != nullptr)
304
17.9k
        return CE_None;
305
306
14.4k
    HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
307
14.4k
    if (poDMS == nullptr)
308
1.51k
    {
309
1.51k
        if (poNode->GetNamedChild("ExternalRasterDMS") != nullptr)
310
120
            return LoadExternalBlockInfo();
311
312
1.39k
        CPLError(CE_Failure, CPLE_AppDefined,
313
1.39k
                 "Can't find RasterDMS field in Eimg_Layer with block list.");
314
315
1.39k
        return CE_Failure;
316
1.51k
    }
317
318
12.9k
    if (sizeof(vsi_l_offset) + 2 * sizeof(int) >
319
12.9k
        (~(size_t)0) / static_cast<unsigned int>(nBlocks))
320
0
    {
321
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Too many blocks");
322
0
        return CE_Failure;
323
0
    }
324
12.9k
    const int MAX_INITIAL_BLOCKS = 1000 * 1000;
325
12.9k
    const int nInitBlocks = std::min(nBlocks, MAX_INITIAL_BLOCKS);
326
12.9k
    panBlockStart = static_cast<vsi_l_offset *>(
327
12.9k
        VSI_MALLOC2_VERBOSE(sizeof(vsi_l_offset), nInitBlocks));
328
12.9k
    panBlockSize =
329
12.9k
        static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nInitBlocks));
330
12.9k
    panBlockFlag =
331
12.9k
        static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nInitBlocks));
332
333
12.9k
    if (panBlockStart == nullptr || panBlockSize == nullptr ||
334
12.9k
        panBlockFlag == nullptr)
335
0
    {
336
0
        CPLFree(panBlockStart);
337
0
        CPLFree(panBlockSize);
338
0
        CPLFree(panBlockFlag);
339
0
        panBlockStart = nullptr;
340
0
        panBlockSize = nullptr;
341
0
        panBlockFlag = nullptr;
342
0
        return CE_Failure;
343
0
    }
344
345
97.6k
    for (int iBlock = 0; iBlock < nBlocks; iBlock++)
346
84.8k
    {
347
84.8k
        CPLErr eErr = CE_None;
348
349
84.8k
        if (iBlock == MAX_INITIAL_BLOCKS)
350
0
        {
351
0
            vsi_l_offset *panBlockStartNew =
352
0
                static_cast<vsi_l_offset *>(VSI_REALLOC_VERBOSE(
353
0
                    panBlockStart, sizeof(vsi_l_offset) * nBlocks));
354
0
            if (panBlockStartNew == nullptr)
355
0
            {
356
0
                CPLFree(panBlockStart);
357
0
                CPLFree(panBlockSize);
358
0
                CPLFree(panBlockFlag);
359
0
                panBlockStart = nullptr;
360
0
                panBlockSize = nullptr;
361
0
                panBlockFlag = nullptr;
362
0
                return CE_Failure;
363
0
            }
364
0
            panBlockStart = panBlockStartNew;
365
366
0
            int *panBlockSizeNew = static_cast<int *>(
367
0
                VSI_REALLOC_VERBOSE(panBlockSize, sizeof(int) * nBlocks));
368
0
            if (panBlockSizeNew == nullptr)
369
0
            {
370
0
                CPLFree(panBlockStart);
371
0
                CPLFree(panBlockSize);
372
0
                CPLFree(panBlockFlag);
373
0
                panBlockStart = nullptr;
374
0
                panBlockSize = nullptr;
375
0
                panBlockFlag = nullptr;
376
0
                return CE_Failure;
377
0
            }
378
0
            panBlockSize = panBlockSizeNew;
379
380
0
            int *panBlockFlagNew = static_cast<int *>(
381
0
                VSI_REALLOC_VERBOSE(panBlockFlag, sizeof(int) * nBlocks));
382
0
            if (panBlockFlagNew == nullptr)
383
0
            {
384
0
                CPLFree(panBlockStart);
385
0
                CPLFree(panBlockSize);
386
0
                CPLFree(panBlockFlag);
387
0
                panBlockStart = nullptr;
388
0
                panBlockSize = nullptr;
389
0
                panBlockFlag = nullptr;
390
0
                return CE_Failure;
391
0
            }
392
0
            panBlockFlag = panBlockFlagNew;
393
0
        }
394
395
84.8k
        char szVarName[64] = {};
396
84.8k
        snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].offset", iBlock);
397
84.8k
        panBlockStart[iBlock] =
398
84.8k
            static_cast<GUInt32>(poDMS->GetIntField(szVarName, &eErr));
399
84.8k
        if (eErr == CE_Failure)
400
180
        {
401
180
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
402
180
            return eErr;
403
180
        }
404
405
84.7k
        snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].size", iBlock);
406
84.7k
        panBlockSize[iBlock] = poDMS->GetIntField(szVarName, &eErr);
407
84.7k
        if (eErr == CE_Failure)
408
8
        {
409
8
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
410
8
            return eErr;
411
8
        }
412
84.6k
        if (panBlockSize[iBlock] < 0)
413
27
        {
414
27
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size");
415
27
            return CE_Failure;
416
27
        }
417
418
84.6k
        snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].logvalid",
419
84.6k
                 iBlock);
420
84.6k
        const int nLogvalid = poDMS->GetIntField(szVarName, &eErr);
421
84.6k
        if (eErr == CE_Failure)
422
16
        {
423
16
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
424
16
            return eErr;
425
16
        }
426
427
84.6k
        snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].compressionType",
428
84.6k
                 iBlock);
429
84.6k
        const int nCompressType = poDMS->GetIntField(szVarName, &eErr);
430
84.6k
        if (eErr == CE_Failure)
431
11
        {
432
11
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
433
11
            return eErr;
434
11
        }
435
436
84.6k
        panBlockFlag[iBlock] = 0;
437
84.6k
        if (nLogvalid)
438
58.1k
            panBlockFlag[iBlock] |= BFLG_VALID;
439
84.6k
        if (nCompressType != 0)
440
58.2k
            panBlockFlag[iBlock] |= BFLG_COMPRESSED;
441
84.6k
    }
442
443
12.7k
    return CE_None;
444
12.9k
}
445
446
/************************************************************************/
447
/*                       LoadExternalBlockInfo()                        */
448
/************************************************************************/
449
450
CPLErr HFABand::LoadExternalBlockInfo()
451
452
120
{
453
120
    if (panBlockFlag != nullptr)
454
0
        return CE_None;
455
456
    // Get the info structure.
457
120
    HFAEntry *poDMS = poNode->GetNamedChild("ExternalRasterDMS");
458
120
    CPLAssert(poDMS != nullptr);
459
460
120
    nLayerStackCount = poDMS->GetIntField("layerStackCount");
461
120
    nLayerStackIndex = poDMS->GetIntField("layerStackIndex");
462
463
    // Open raw data file.
464
120
    const std::string osFullFilename = HFAGetIGEFilename(psInfo);
465
120
    if (osFullFilename.empty())
466
51
    {
467
51
        CPLError(CE_Failure, CPLE_OpenFailed,
468
51
                 "Cannot find external data file name");
469
51
        return CE_Failure;
470
51
    }
471
472
69
    if (psInfo->eAccess == HFA_ReadOnly)
473
69
        fpExternal = VSIFOpenL(osFullFilename.c_str(), "rb");
474
0
    else
475
0
        fpExternal = VSIFOpenL(osFullFilename.c_str(), "r+b");
476
69
    if (fpExternal == nullptr)
477
55
    {
478
55
        CPLError(CE_Failure, CPLE_OpenFailed,
479
55
                 "Unable to open external data file: %s",
480
55
                 osFullFilename.c_str());
481
55
        return CE_Failure;
482
55
    }
483
484
    // Verify header.
485
14
    char szHeader[49] = {};
486
487
14
    if (VSIFReadL(szHeader, sizeof(szHeader), 1, fpExternal) != 1 ||
488
14
        !STARTS_WITH(szHeader, "ERDAS_IMG_EXTERNAL_RASTER"))
489
14
    {
490
14
        CPLError(CE_Failure, CPLE_AppDefined,
491
14
                 "Raw data file %s appears to be corrupt.",
492
14
                 osFullFilename.c_str());
493
14
        return CE_Failure;
494
14
    }
495
496
    // Allocate blockmap.
497
0
    panBlockFlag =
498
0
        static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nBlocks));
499
0
    if (panBlockFlag == nullptr)
500
0
    {
501
0
        return CE_Failure;
502
0
    }
503
504
    // Load the validity bitmap.
505
0
    const int nBytesPerRow = (nBlocksPerRow + 7) / 8;
506
0
    unsigned char *pabyBlockMap = static_cast<unsigned char *>(
507
0
        VSI_MALLOC_VERBOSE(nBytesPerRow * nBlocksPerColumn + 20));
508
0
    if (pabyBlockMap == nullptr)
509
0
    {
510
0
        return CE_Failure;
511
0
    }
512
513
0
    if (VSIFSeekL(fpExternal,
514
0
                  static_cast<vsi_l_offset>(
515
0
                      poDMS->GetBigIntField("layerStackValidFlagsOffset")),
516
0
                  SEEK_SET) < 0 ||
517
0
        VSIFReadL(pabyBlockMap, nBytesPerRow * nBlocksPerColumn + 20, 1,
518
0
                  fpExternal) != 1)
519
0
    {
520
0
        CPLError(CE_Failure, CPLE_FileIO, "Failed to read block validity map.");
521
0
        return CE_Failure;
522
0
    }
523
524
    // Establish block information.  Block position is computed
525
    // from data base address.  Blocks are never compressed.
526
    // Validity is determined from the validity bitmap.
527
528
0
    nBlockStart = poDMS->GetBigIntField("layerStackDataOffset");
529
0
    nBlockSize = (nBlockXSize * static_cast<vsi_l_offset>(nBlockYSize) *
530
0
                      HFAGetDataTypeBits(eDataType) +
531
0
                  7) /
532
0
                 8;
533
534
0
    for (int iBlock = 0; iBlock < nBlocks; iBlock++)
535
0
    {
536
0
        const int nColumn = iBlock % nBlocksPerRow;
537
0
        const int nRow = iBlock / nBlocksPerRow;
538
0
        const int nBit = nRow * nBytesPerRow * 8 + nColumn + 20 * 8;
539
540
0
        if ((pabyBlockMap[nBit >> 3] >> (nBit & 7)) & 0x1)
541
0
            panBlockFlag[iBlock] = BFLG_VALID;
542
0
        else
543
0
            panBlockFlag[iBlock] = 0;
544
0
    }
545
546
0
    CPLFree(pabyBlockMap);
547
548
0
    return CE_None;
549
0
}
550
551
/************************************************************************/
552
/*                          UncompressBlock()                           */
553
/*                                                                      */
554
/*      Uncompress ESRI Grid compression format block.                  */
555
/************************************************************************/
556
557
// TODO(schwehr): Get rid of this macro without a goto.
558
#define CHECK_ENOUGH_BYTES(n)                                                  \
559
1.26M
    if (nSrcBytes < (n))                                                       \
560
1.26M
    {                                                                          \
561
294
        CPLError(CE_Failure, CPLE_AppDefined,                                  \
562
294
                 "Not enough bytes in compressed block");                      \
563
294
        return CE_Failure;                                                     \
564
294
    }
565
566
static CPLErr UncompressBlock(GByte *pabyCData, int nSrcBytes, GByte *pabyDest,
567
                              int nMaxPixels, EPTType eDataType)
568
569
7.47k
{
570
7.47k
    CHECK_ENOUGH_BYTES(13);
571
572
7.45k
    const GUInt32 nDataMin = CPL_LSBUINT32PTR(pabyCData);
573
7.45k
    const GInt32 nNumRuns = CPL_LSBSINT32PTR(pabyCData + 4);
574
7.45k
    const GInt32 nDataOffset = CPL_LSBSINT32PTR(pabyCData + 8);
575
576
7.45k
    const int nNumBits = pabyCData[12];
577
578
    // If this is not run length encoded, but just reduced
579
    // precision, handle it now.
580
581
7.45k
    int nPixelsOutput = 0;
582
7.45k
    GByte *pabyValues = nullptr;
583
7.45k
    int nValueBitOffset = 0;
584
585
7.45k
    if (nNumRuns == -1)
586
253
    {
587
253
        pabyValues = pabyCData + 13;
588
253
        nValueBitOffset = 0;
589
590
253
        if (nNumBits > INT_MAX / nMaxPixels ||
591
253
            nNumBits * nMaxPixels > INT_MAX - 7 ||
592
253
            (nNumBits * nMaxPixels + 7) / 8 > INT_MAX - 13)
593
0
        {
594
0
            CPLError(CE_Failure, CPLE_AppDefined,
595
0
                     "Integer overflow : nNumBits * nMaxPixels + 7");
596
0
            return CE_Failure;
597
0
        }
598
253
        CHECK_ENOUGH_BYTES(13 + (nNumBits * nMaxPixels + 7) / 8);
599
600
        // Loop over block pixels.
601
11.2M
        for (nPixelsOutput = 0; nPixelsOutput < nMaxPixels; nPixelsOutput++)
602
11.2M
        {
603
            // Extract the data value in a way that depends on the number
604
            // of bits in it.
605
606
11.2M
            int nRawValue = 0;
607
608
11.2M
            if (nNumBits == 0)
609
10.9M
            {
610
                // nRawValue = 0;
611
10.9M
            }
612
363k
            else if (nNumBits == 1)
613
20.6k
            {
614
20.6k
                nRawValue = (pabyValues[nValueBitOffset >> 3] >>
615
20.6k
                             (nValueBitOffset & 7)) &
616
20.6k
                            0x1;
617
20.6k
                nValueBitOffset++;
618
20.6k
            }
619
343k
            else if (nNumBits == 2)
620
646
            {
621
646
                nRawValue = (pabyValues[nValueBitOffset >> 3] >>
622
646
                             (nValueBitOffset & 7)) &
623
646
                            0x3;
624
646
                nValueBitOffset += 2;
625
646
            }
626
342k
            else if (nNumBits == 4)
627
1.29k
            {
628
1.29k
                nRawValue = (pabyValues[nValueBitOffset >> 3] >>
629
1.29k
                             (nValueBitOffset & 7)) &
630
1.29k
                            0xf;
631
1.29k
                nValueBitOffset += 4;
632
1.29k
            }
633
341k
            else if (nNumBits == 8)
634
152k
            {
635
152k
                nRawValue = *pabyValues;
636
152k
                pabyValues++;
637
152k
            }
638
188k
            else if (nNumBits == 16)
639
188k
            {
640
188k
                nRawValue = 256 * *(pabyValues++);
641
188k
                nRawValue += *(pabyValues++);
642
188k
            }
643
75
            else if (nNumBits == 32)
644
65
            {
645
65
                memcpy(&nRawValue, pabyValues, 4);
646
65
                CPL_MSBPTR32(&nRawValue);
647
65
                pabyValues += 4;
648
65
            }
649
10
            else
650
10
            {
651
10
                CPLError(CE_Failure, CPLE_NotSupported,
652
10
                         "Unsupported nNumBits value: %d", nNumBits);
653
10
                return CE_Failure;
654
10
            }
655
656
            // Offset by the minimum value.
657
11.2M
            const int nDataValue = CPLUnsanitizedAdd<int>(nRawValue, nDataMin);
658
659
            // Now apply to the output buffer in a type specific way.
660
11.2M
            if (eDataType == EPT_u8)
661
175k
            {
662
175k
                pabyDest[nPixelsOutput] = static_cast<GByte>(nDataValue);
663
175k
            }
664
11.1M
            else if (eDataType == EPT_u1)
665
28.8k
            {
666
28.8k
                if (nDataValue == 1)
667
6.23k
                    pabyDest[nPixelsOutput >> 3] |=
668
6.23k
                        (1 << (nPixelsOutput & 0x7));
669
22.6k
                else
670
22.6k
                    pabyDest[nPixelsOutput >> 3] &=
671
22.6k
                        ~(1 << (nPixelsOutput & 0x7));
672
28.8k
            }
673
11.0M
            else if (eDataType == EPT_u2)
674
9.49M
            {
675
                // nDataValue & 0x3 is just to avoid UBSAN warning on shifting
676
                // negative values
677
9.49M
                if ((nPixelsOutput & 0x3) == 0)
678
2.37M
                    pabyDest[nPixelsOutput >> 2] =
679
2.37M
                        static_cast<GByte>(nDataValue);
680
7.11M
                else if ((nPixelsOutput & 0x3) == 1)
681
2.37M
                    pabyDest[nPixelsOutput >> 2] |=
682
2.37M
                        static_cast<GByte>((nDataValue & 0x3) << 2);
683
4.74M
                else if ((nPixelsOutput & 0x3) == 2)
684
2.37M
                    pabyDest[nPixelsOutput >> 2] |=
685
2.37M
                        static_cast<GByte>((nDataValue & 0x3) << 4);
686
2.37M
                else
687
2.37M
                    pabyDest[nPixelsOutput >> 2] |=
688
2.37M
                        static_cast<GByte>((nDataValue & 0x3) << 6);
689
9.49M
            }
690
1.59M
            else if (eDataType == EPT_u4)
691
9.70k
            {
692
                // nDataValue & 0xF is just to avoid UBSAN warning on shifting
693
                // negative values
694
9.70k
                if ((nPixelsOutput & 0x1) == 0)
695
4.85k
                    pabyDest[nPixelsOutput >> 1] =
696
4.85k
                        static_cast<GByte>(nDataValue);
697
4.84k
                else
698
4.84k
                    pabyDest[nPixelsOutput >> 1] |=
699
4.84k
                        static_cast<GByte>((nDataValue & 0xF) << 4);
700
9.70k
            }
701
1.58M
            else if (eDataType == EPT_s8)
702
331
            {
703
331
                reinterpret_cast<GInt8 *>(pabyDest)[nPixelsOutput] =
704
331
                    static_cast<GInt8>(nDataValue);
705
331
            }
706
1.58M
            else if (eDataType == EPT_u16)
707
358
            {
708
358
                reinterpret_cast<GUInt16 *>(pabyDest)[nPixelsOutput] =
709
358
                    static_cast<GUInt16>(nDataValue);
710
358
            }
711
1.58M
            else if (eDataType == EPT_s16)
712
450
            {
713
450
                reinterpret_cast<GInt16 *>(pabyDest)[nPixelsOutput] =
714
450
                    static_cast<GInt16>(nDataValue);
715
450
            }
716
1.58M
            else if (eDataType == EPT_s32)
717
151k
            {
718
151k
                reinterpret_cast<GInt32 *>(pabyDest)[nPixelsOutput] =
719
151k
                    nDataValue;
720
151k
            }
721
1.43M
            else if (eDataType == EPT_u32)
722
786k
            {
723
786k
                reinterpret_cast<GUInt32 *>(pabyDest)[nPixelsOutput] =
724
786k
                    nDataValue;
725
786k
            }
726
650k
            else if (eDataType == EPT_f32)
727
650k
            {
728
                // Note, floating point values are handled as if they were
729
                // signed 32-bit integers (bug #1000).
730
650k
                memcpy(&(reinterpret_cast<float *>(pabyDest)[nPixelsOutput]),
731
650k
                       &nDataValue, sizeof(float));
732
650k
            }
733
10
            else
734
10
            {
735
10
                CPLError(
736
10
                    CE_Failure, CPLE_AppDefined,
737
10
                    "Attempt to uncompress an unsupported pixel data type.");
738
10
                return CE_Failure;
739
10
            }
740
11.2M
        }
741
742
212
        return CE_None;
743
232
    }
744
745
    // Establish data pointers for runs.
746
7.19k
    if (nNumRuns < 0 || nDataOffset < 0)
747
64
    {
748
64
        CPLError(CE_Failure, CPLE_AppDefined, "nNumRuns=%d, nDataOffset=%d",
749
64
                 nNumRuns, nDataOffset);
750
64
        return CE_Failure;
751
64
    }
752
753
7.13k
    if (nNumRuns != 0 &&
754
5.76k
        (nNumBits > INT_MAX / nNumRuns || nNumBits * nNumRuns > INT_MAX - 7 ||
755
5.68k
         (nNumBits * nNumRuns + 7) / 8 > INT_MAX - nDataOffset))
756
83
    {
757
83
        CPLError(CE_Failure, CPLE_AppDefined,
758
83
                 "Integer overflow: nDataOffset + (nNumBits * nNumRuns + 7)/8");
759
83
        return CE_Failure;
760
83
    }
761
7.05k
    CHECK_ENOUGH_BYTES(nDataOffset + (nNumBits * nNumRuns + 7) / 8);
762
763
6.96k
    GByte *pabyCounter = pabyCData + 13;
764
6.96k
    int nCounterOffset = 13;
765
6.96k
    pabyValues = pabyCData + nDataOffset;
766
6.96k
    nValueBitOffset = 0;
767
768
    // Loop over runs.
769
1.00M
    for (int iRun = 0; iRun < nNumRuns; iRun++)
770
999k
    {
771
999k
        int nRepeatCount = 0;
772
773
        // Get the repeat count.  This can be stored as one, two, three
774
        // or four bytes depending on the low order two bits of the
775
        // first byte.
776
999k
        CHECK_ENOUGH_BYTES(nCounterOffset + 1);
777
998k
        if ((*pabyCounter & 0xc0) == 0x00)
778
750k
        {
779
750k
            nRepeatCount = (*(pabyCounter++)) & 0x3f;
780
750k
            nCounterOffset++;
781
750k
        }
782
248k
        else if (((*pabyCounter) & 0xc0) == 0x40)
783
190k
        {
784
190k
            CHECK_ENOUGH_BYTES(nCounterOffset + 2);
785
190k
            nRepeatCount = (*(pabyCounter++)) & 0x3f;
786
190k
            nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
787
190k
            nCounterOffset += 2;
788
190k
        }
789
58.0k
        else if (((*pabyCounter) & 0xc0) == 0x80)
790
33.8k
        {
791
33.8k
            CHECK_ENOUGH_BYTES(nCounterOffset + 3);
792
33.8k
            nRepeatCount = (*(pabyCounter++)) & 0x3f;
793
33.8k
            nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
794
33.8k
            nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
795
33.8k
            nCounterOffset += 3;
796
33.8k
        }
797
24.2k
        else if (((*pabyCounter) & 0xc0) == 0xc0)
798
24.2k
        {
799
24.2k
            CHECK_ENOUGH_BYTES(nCounterOffset + 4);
800
24.1k
            nRepeatCount = (*(pabyCounter++)) & 0x3f;
801
24.1k
            nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
802
24.1k
            nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
803
24.1k
            nRepeatCount = nRepeatCount * 256 + (*(pabyCounter++));
804
24.1k
            nCounterOffset += 4;
805
24.1k
        }
806
807
        // Extract the data value in a way that depends on the number
808
        // of bits in it.
809
998k
        int nDataValue = 0;
810
811
998k
        if (nNumBits == 0)
812
405k
        {
813
            // nDataValue = 0;
814
405k
        }
815
593k
        else if (nNumBits == 1)
816
66.2k
        {
817
66.2k
            nDataValue =
818
66.2k
                (pabyValues[nValueBitOffset >> 3] >> (nValueBitOffset & 7)) &
819
66.2k
                0x1;
820
66.2k
            nValueBitOffset++;
821
66.2k
        }
822
527k
        else if (nNumBits == 2)
823
27.3k
        {
824
27.3k
            nDataValue =
825
27.3k
                (pabyValues[nValueBitOffset >> 3] >> (nValueBitOffset & 7)) &
826
27.3k
                0x3;
827
27.3k
            nValueBitOffset += 2;
828
27.3k
        }
829
499k
        else if (nNumBits == 4)
830
19.2k
        {
831
19.2k
            nDataValue =
832
19.2k
                (pabyValues[nValueBitOffset >> 3] >> (nValueBitOffset & 7)) &
833
19.2k
                0xf;
834
19.2k
            nValueBitOffset += 4;
835
19.2k
        }
836
480k
        else if (nNumBits == 8)
837
176k
        {
838
176k
            nDataValue = *pabyValues;
839
176k
            pabyValues++;
840
176k
        }
841
304k
        else if (nNumBits == 16)
842
125k
        {
843
125k
            nDataValue = 256 * *(pabyValues++);
844
125k
            nDataValue += *(pabyValues++);
845
125k
        }
846
179k
        else if (nNumBits == 32)
847
178k
        {
848
178k
            memcpy(&nDataValue, pabyValues, 4);
849
178k
            CPL_MSBPTR32(&nDataValue);
850
178k
            pabyValues += 4;
851
178k
        }
852
11
        else
853
11
        {
854
11
            CPLError(CE_Failure, CPLE_NotSupported, "nNumBits = %d", nNumBits);
855
11
            return CE_Failure;
856
11
        }
857
858
        // Offset by the minimum value.
859
998k
        nDataValue = CPLUnsanitizedAdd<int>(nDataValue, nDataMin);
860
861
        // Now apply to the output buffer in a type specific way.
862
998k
        if (nRepeatCount > INT_MAX - nPixelsOutput ||
863
998k
            nPixelsOutput + nRepeatCount > nMaxPixels)
864
400k
        {
865
400k
            CPLDebug("HFA", "Repeat count too big: %d", nRepeatCount);
866
400k
            nRepeatCount = nMaxPixels - nPixelsOutput;
867
400k
        }
868
869
998k
        if (eDataType == EPT_u8)
870
261k
        {
871
18.5M
            for (int i = 0; i < nRepeatCount; i++)
872
18.3M
            {
873
#if DEBUG_VERBOSE
874
                // TODO(schwehr): Do something smarter with out-of-range data.
875
                // Bad data can trigger this assert.  r23498
876
                CPLAssert(nDataValue < 256);
877
#endif
878
18.3M
                pabyDest[nPixelsOutput++] = static_cast<GByte>(nDataValue);
879
18.3M
            }
880
261k
        }
881
737k
        else if (eDataType == EPT_u16)
882
14.9k
        {
883
28.1M
            for (int i = 0; i < nRepeatCount; i++)
884
28.1M
            {
885
#if DEBUG_VERBOSE
886
                CPLAssert(nDataValue >= 0);
887
                CPLAssert(nDataValue < 65536);
888
#endif
889
28.1M
                reinterpret_cast<GUInt16 *>(pabyDest)[nPixelsOutput++] =
890
28.1M
                    static_cast<GUInt16>(nDataValue);
891
28.1M
            }
892
14.9k
        }
893
722k
        else if (eDataType == EPT_s8)
894
18.9k
        {
895
17.0M
            for (int i = 0; i < nRepeatCount; i++)
896
16.9M
            {
897
#if DEBUG_VERBOSE
898
                // TODO(schwehr): Do something smarter with out-of-range data.
899
                // Bad data can trigger this assert.  r23498
900
                CPLAssert(nDataValue >= -127);
901
                CPLAssert(nDataValue < 128);
902
#endif
903
16.9M
                ((GByte *)pabyDest)[nPixelsOutput++] =
904
16.9M
                    static_cast<GByte>(nDataValue);
905
16.9M
            }
906
18.9k
        }
907
703k
        else if (eDataType == EPT_s16)
908
25.2k
        {
909
20.0M
            for (int i = 0; i < nRepeatCount; i++)
910
20.0M
            {
911
#if DEBUG_VERBOSE
912
                // TODO(schwehr): Do something smarter with out-of-range data.
913
                // Bad data can trigger this assert.  r23498
914
                CPLAssert(nDataValue >= -32768);
915
                CPLAssert(nDataValue < 32768);
916
#endif
917
20.0M
                reinterpret_cast<GInt16 *>(pabyDest)[nPixelsOutput++] =
918
20.0M
                    static_cast<GInt16>(nDataValue);
919
20.0M
            }
920
25.2k
        }
921
678k
        else if (eDataType == EPT_u32)
922
18.0k
        {
923
14.9M
            for (int i = 0; i < nRepeatCount; i++)
924
14.9M
            {
925
#if DEBUG_VERBOSE
926
                // TODO(schwehr): Do something smarter with out-of-range data.
927
                // Bad data can trigger this assert.  r23498
928
                CPLAssert(nDataValue >= 0);
929
#endif
930
14.9M
                reinterpret_cast<GUInt32 *>(pabyDest)[nPixelsOutput++] =
931
14.9M
                    static_cast<GUInt32>(nDataValue);
932
14.9M
            }
933
18.0k
        }
934
660k
        else if (eDataType == EPT_s32)
935
147k
        {
936
17.3M
            for (int i = 0; i < nRepeatCount; i++)
937
17.2M
            {
938
17.2M
                reinterpret_cast<GInt32 *>(pabyDest)[nPixelsOutput++] =
939
17.2M
                    static_cast<GInt32>(nDataValue);
940
17.2M
            }
941
147k
        }
942
512k
        else if (eDataType == EPT_f32)
943
210k
        {
944
210k
            float fDataValue = 0.0f;
945
946
210k
            memcpy(&fDataValue, &nDataValue, 4);
947
1.59M
            for (int i = 0; i < nRepeatCount; i++)
948
1.38M
            {
949
1.38M
                reinterpret_cast<float *>(pabyDest)[nPixelsOutput++] =
950
1.38M
                    fDataValue;
951
1.38M
            }
952
210k
        }
953
301k
        else if (eDataType == EPT_u1)
954
235k
        {
955
#ifdef DEBUG_VERBOSE
956
            CPLAssert(nDataValue == 0 || nDataValue == 1);
957
#endif
958
235k
            if (nDataValue == 1)
959
57.4k
            {
960
1.94M
                for (int i = 0; i < nRepeatCount; i++)
961
1.88M
                {
962
1.88M
                    pabyDest[nPixelsOutput >> 3] |=
963
1.88M
                        (1 << (nPixelsOutput & 0x7));
964
1.88M
                    nPixelsOutput++;
965
1.88M
                }
966
57.4k
            }
967
177k
            else
968
177k
            {
969
80.8M
                for (int i = 0; i < nRepeatCount; i++)
970
80.7M
                {
971
80.7M
                    pabyDest[nPixelsOutput >> 3] &=
972
80.7M
                        ~(1 << (nPixelsOutput & 0x7));
973
80.7M
                    nPixelsOutput++;
974
80.7M
                }
975
177k
            }
976
235k
        }
977
66.4k
        else if (eDataType == EPT_u2)
978
29.3k
        {
979
#ifdef DEBUG_VERBOSE
980
            CPLAssert(nDataValue >= 0 && nDataValue < 4);
981
#endif
982
24.7M
            for (int i = 0; i < nRepeatCount; i++)
983
24.7M
            {
984
24.7M
                if ((nPixelsOutput & 0x3) == 0)
985
6.18M
                    pabyDest[nPixelsOutput >> 2] =
986
6.18M
                        static_cast<GByte>(nDataValue);
987
18.5M
                else if ((nPixelsOutput & 0x3) == 1)
988
6.18M
                    pabyDest[nPixelsOutput >> 2] |=
989
6.18M
                        static_cast<GByte>((nDataValue & 0x3) << 2);
990
12.3M
                else if ((nPixelsOutput & 0x3) == 2)
991
6.18M
                    pabyDest[nPixelsOutput >> 2] |=
992
6.18M
                        static_cast<GByte>((nDataValue & 0x3) << 4);
993
6.18M
                else
994
6.18M
                    pabyDest[nPixelsOutput >> 2] |=
995
6.18M
                        static_cast<GByte>((nDataValue & 0x3) << 6);
996
24.7M
                nPixelsOutput++;
997
24.7M
            }
998
29.3k
        }
999
37.1k
        else if (eDataType == EPT_u4)
1000
37.1k
        {
1001
#ifdef DEBUG_VERBOSE
1002
            CPLAssert(nDataValue >= 0 && nDataValue < 16);
1003
#endif
1004
99.4M
            for (int i = 0; i < nRepeatCount; i++)
1005
99.3M
            {
1006
99.3M
                if ((nPixelsOutput & 0x1) == 0)
1007
49.6M
                    pabyDest[nPixelsOutput >> 1] =
1008
49.6M
                        static_cast<GByte>(nDataValue);
1009
49.6M
                else
1010
49.6M
                    pabyDest[nPixelsOutput >> 1] |=
1011
49.6M
                        static_cast<GByte>((nDataValue & 0xF) << 4);
1012
1013
99.3M
                nPixelsOutput++;
1014
99.3M
            }
1015
37.1k
        }
1016
21
        else
1017
21
        {
1018
21
            CPLError(CE_Failure, CPLE_AppDefined,
1019
21
                     "Attempt to uncompress an unsupported pixel data type.");
1020
21
            return CE_Failure;
1021
21
        }
1022
998k
    }
1023
1024
6.76k
    return CE_None;
1025
6.96k
}
1026
1027
/************************************************************************/
1028
/*                             NullBlock()                              */
1029
/*                                                                      */
1030
/*      Set the block buffer to zero or the nodata value as             */
1031
/*      appropriate.                                                    */
1032
/************************************************************************/
1033
1034
void HFABand::NullBlock(void *pData)
1035
1036
1.65k
{
1037
1.65k
    const int nChunkSize = std::max(1, HFAGetDataTypeBits(eDataType) / 8);
1038
1.65k
    int nWords = nBlockXSize * nBlockYSize;
1039
1040
1.65k
    if (!bNoDataSet)
1041
872
    {
1042
#ifdef ESRI_BUILD
1043
        // We want special defaulting for 1 bit data in ArcGIS.
1044
        if (eDataType >= EPT_u2)
1045
            memset(pData, 0, static_cast<size_t>(nChunkSize) * nWords);
1046
        else
1047
            memset(pData, 255, static_cast<size_t>(nChunkSize) * nWords);
1048
#else
1049
872
        memset(pData, 0, static_cast<size_t>(nChunkSize) * nWords);
1050
872
#endif
1051
872
    }
1052
785
    else
1053
785
    {
1054
785
        GByte abyTmp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1055
1056
785
        switch (eDataType)
1057
785
        {
1058
169
            case EPT_u1:
1059
169
            {
1060
169
                nWords = (nWords + 7) / 8;
1061
169
                if (dfNoData != 0.0)
1062
88
                    ((unsigned char *)abyTmp)[0] = 0xff;
1063
81
                else
1064
81
                    ((unsigned char *)abyTmp)[0] = 0x00;
1065
169
            }
1066
169
            break;
1067
1068
49
            case EPT_u2:
1069
49
            {
1070
49
                nWords = (nWords + 3) / 4;
1071
49
                if (dfNoData == 0.0)
1072
19
                    ((unsigned char *)abyTmp)[0] = 0x00;
1073
30
                else if (dfNoData == 1.0)
1074
25
                    ((unsigned char *)abyTmp)[0] = 0x55;
1075
5
                else if (dfNoData == 2.0)
1076
0
                    ((unsigned char *)abyTmp)[0] = 0xaa;
1077
5
                else
1078
5
                    ((unsigned char *)abyTmp)[0] = 0xff;
1079
49
            }
1080
49
            break;
1081
1082
207
            case EPT_u4:
1083
207
            {
1084
207
                const unsigned char byVal = static_cast<unsigned char>(
1085
207
                    std::max(0, std::min(15, static_cast<int>(dfNoData))));
1086
1087
207
                nWords = (nWords + 1) / 2;
1088
1089
207
                ((unsigned char *)abyTmp)[0] = byVal + (byVal << 4);
1090
207
            }
1091
207
            break;
1092
1093
69
            case EPT_u8:
1094
69
                ((unsigned char *)abyTmp)[0] = static_cast<unsigned char>(
1095
69
                    std::max(0, std::min(255, static_cast<int>(dfNoData))));
1096
69
                break;
1097
1098
0
            case EPT_s8:
1099
0
                ((signed char *)abyTmp)[0] = static_cast<signed char>(
1100
0
                    std::max(-128, std::min(127, static_cast<int>(dfNoData))));
1101
0
                break;
1102
1103
62
            case EPT_u16:
1104
62
            {
1105
62
                GUInt16 nTmp = static_cast<GUInt16>(dfNoData);
1106
62
                memcpy(abyTmp, &nTmp, sizeof(nTmp));
1107
62
                break;
1108
0
            }
1109
1110
44
            case EPT_s16:
1111
44
            {
1112
44
                GInt16 nTmp = static_cast<GInt16>(dfNoData);
1113
44
                memcpy(abyTmp, &nTmp, sizeof(nTmp));
1114
44
                break;
1115
0
            }
1116
1117
31
            case EPT_u32:
1118
31
            {
1119
31
                GUInt32 nTmp = static_cast<GUInt32>(dfNoData);
1120
31
                memcpy(abyTmp, &nTmp, sizeof(nTmp));
1121
31
                break;
1122
0
            }
1123
1124
0
            case EPT_s32:
1125
0
            {
1126
0
                GInt32 nTmp = static_cast<GInt32>(dfNoData);
1127
0
                memcpy(abyTmp, &nTmp, sizeof(nTmp));
1128
0
                break;
1129
0
            }
1130
1131
65
            case EPT_f32:
1132
65
            {
1133
65
                float fTmp = static_cast<float>(dfNoData);
1134
65
                memcpy(abyTmp, &fTmp, sizeof(fTmp));
1135
65
                break;
1136
0
            }
1137
1138
10
            case EPT_f64:
1139
10
            {
1140
10
                memcpy(abyTmp, &dfNoData, sizeof(dfNoData));
1141
10
                break;
1142
0
            }
1143
1144
79
            case EPT_c64:
1145
79
            {
1146
79
                float fTmp = static_cast<float>(dfNoData);
1147
79
                memcpy(abyTmp, &fTmp, sizeof(fTmp));
1148
79
                memset(abyTmp + 4, 0, sizeof(float));
1149
79
                break;
1150
0
            }
1151
1152
0
            case EPT_c128:
1153
0
            {
1154
0
                memcpy(abyTmp, &dfNoData, sizeof(dfNoData));
1155
0
                memset(abyTmp + 8, 0, sizeof(double));
1156
0
                break;
1157
0
            }
1158
785
        }
1159
1160
3.21M
        for (int i = 0; i < nWords; i++)
1161
3.20M
            memcpy(((GByte *)pData) + nChunkSize * i, abyTmp, nChunkSize);
1162
785
    }
1163
1.65k
}
1164
1165
/************************************************************************/
1166
/*                           GetRasterBlock()                           */
1167
/************************************************************************/
1168
1169
CPLErr HFABand::GetRasterBlock(int nXBlock, int nYBlock, void *pData,
1170
                               int nDataSize)
1171
1172
12.3k
{
1173
12.3k
    if (LoadBlockInfo() != CE_None)
1174
1.75k
        return CE_Failure;
1175
1176
10.5k
    const int iBlock = nXBlock + nYBlock * nBlocksPerRow;
1177
10.5k
    const int nDataTypeSizeBytes =
1178
10.5k
        std::max(1, HFAGetDataTypeBits(eDataType) / 8);
1179
10.5k
    const int nGDALBlockSize = nDataTypeSizeBytes * nBlockXSize * nBlockYSize;
1180
1181
    // If the block isn't valid, we just return all zeros, and an
1182
    // indication of success.
1183
10.5k
    if ((panBlockFlag[iBlock] & BFLG_VALID) == 0)
1184
1.65k
    {
1185
1.65k
        NullBlock(pData);
1186
1.65k
        return CE_None;
1187
1.65k
    }
1188
1189
    // Otherwise we really read the data.
1190
8.94k
    vsi_l_offset nBlockOffset = 0;
1191
8.94k
    VSILFILE *fpData = nullptr;
1192
1193
    // Calculate block offset in case we have spill file. Use predefined
1194
    // block map otherwise.
1195
8.94k
    if (fpExternal)
1196
0
    {
1197
0
        fpData = fpExternal;
1198
0
        nBlockOffset = nBlockStart + nBlockSize * iBlock * nLayerStackCount +
1199
0
                       nLayerStackIndex * nBlockSize;
1200
0
    }
1201
8.94k
    else
1202
8.94k
    {
1203
8.94k
        fpData = psInfo->fp;
1204
8.94k
        nBlockOffset = panBlockStart[iBlock];
1205
8.94k
        nBlockSize = panBlockSize[iBlock];
1206
8.94k
    }
1207
1208
8.94k
    if (VSIFSeekL(fpData, nBlockOffset, SEEK_SET) != 0)
1209
0
    {
1210
        // XXX: We will not report error here, because file just may be
1211
        // in update state and data for this block will be available later.
1212
0
        if (psInfo->eAccess == HFA_Update)
1213
0
        {
1214
0
            memset(pData, 0, nGDALBlockSize);
1215
0
            return CE_None;
1216
0
        }
1217
0
        else
1218
0
        {
1219
0
            CPLError(CE_Failure, CPLE_FileIO,
1220
0
                     "Seek to %x:%08x on %p failed\n%s",
1221
0
                     static_cast<int>(nBlockOffset >> 32),
1222
0
                     static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1223
0
                     VSIStrerror(errno));
1224
0
            return CE_Failure;
1225
0
        }
1226
0
    }
1227
1228
    // If the block is compressed, read into an intermediate buffer
1229
    // and convert.
1230
8.94k
    if (panBlockFlag[iBlock] & BFLG_COMPRESSED)
1231
7.60k
    {
1232
7.60k
        GByte *pabyCData = static_cast<GByte *>(
1233
7.60k
            VSI_MALLOC_VERBOSE(static_cast<size_t>(nBlockSize)));
1234
7.60k
        if (pabyCData == nullptr)
1235
0
        {
1236
0
            return CE_Failure;
1237
0
        }
1238
1239
7.60k
        if (VSIFReadL(pabyCData, static_cast<size_t>(nBlockSize), 1, fpData) !=
1240
7.60k
            1)
1241
136
        {
1242
136
            CPLFree(pabyCData);
1243
1244
            // XXX: Suppose that file in update state
1245
136
            if (psInfo->eAccess == HFA_Update)
1246
0
            {
1247
0
                memset(pData, 0, nGDALBlockSize);
1248
0
                return CE_None;
1249
0
            }
1250
136
            else
1251
136
            {
1252
136
                CPLError(CE_Failure, CPLE_FileIO,
1253
136
                         "Read of %d bytes at %x:%08x on %p failed.\n%s",
1254
136
                         static_cast<int>(nBlockSize),
1255
136
                         static_cast<int>(nBlockOffset >> 32),
1256
136
                         static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1257
136
                         VSIStrerror(errno));
1258
136
                return CE_Failure;
1259
136
            }
1260
136
        }
1261
1262
7.47k
        CPLErr eErr = UncompressBlock(pabyCData, static_cast<int>(nBlockSize),
1263
7.47k
                                      static_cast<GByte *>(pData),
1264
7.47k
                                      nBlockXSize * nBlockYSize, eDataType);
1265
1266
7.47k
        CPLFree(pabyCData);
1267
1268
7.47k
        return eErr;
1269
7.60k
    }
1270
1271
    // Read uncompressed data directly into the return buffer.
1272
1.33k
    if (nDataSize != -1 &&
1273
1.33k
        (nBlockSize > INT_MAX || static_cast<int>(nBlockSize) > nDataSize))
1274
35
    {
1275
35
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size: %d",
1276
35
                 static_cast<int>(nBlockSize));
1277
35
        return CE_Failure;
1278
35
    }
1279
1280
1.30k
    if (VSIFReadL(pData, static_cast<size_t>(nBlockSize), 1, fpData) != 1)
1281
676
    {
1282
676
        memset(pData, 0, nGDALBlockSize);
1283
1284
676
        if (fpData != fpExternal)
1285
676
            CPLDebug("HFABand", "Read of %x:%08x bytes at %d on %p failed.\n%s",
1286
676
                     static_cast<int>(nBlockSize),
1287
676
                     static_cast<int>(nBlockOffset >> 32),
1288
676
                     static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1289
676
                     VSIStrerror(errno));
1290
1291
676
        return CE_None;
1292
676
    }
1293
1294
    // Byte swap to local byte order if required.  It appears that
1295
    // raster data is always stored in Intel byte order in Imagine
1296
    // files.
1297
1298
#ifdef CPL_MSB
1299
    if (HFAGetDataTypeBits(eDataType) == 16)
1300
    {
1301
        for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1302
            CPL_SWAP16PTR(((unsigned char *)pData) + ii * 2);
1303
    }
1304
    else if (HFAGetDataTypeBits(eDataType) == 32)
1305
    {
1306
        for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1307
            CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1308
    }
1309
    else if (eDataType == EPT_f64)
1310
    {
1311
        for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1312
            CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1313
    }
1314
    else if (eDataType == EPT_c64)
1315
    {
1316
        for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1317
            CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1318
    }
1319
    else if (eDataType == EPT_c128)
1320
    {
1321
        for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1322
            CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1323
    }
1324
#endif  // def CPL_MSB
1325
1326
625
    return CE_None;
1327
1.30k
}
1328
1329
/************************************************************************/
1330
/*                            ReAllocBlock()                            */
1331
/************************************************************************/
1332
1333
void HFABand::ReAllocBlock(int iBlock, int nSize)
1334
1.60k
{
1335
    // For compressed files - need to realloc the space for the block.
1336
1337
    // TODO: Should check to see if panBlockStart[iBlock] is not zero then do a
1338
    // HFAFreeSpace() but that doesn't exist yet.
1339
    // Instead as in interim measure it will reuse the existing block if
1340
    // the new data will fit in.
1341
1.60k
    if ((panBlockStart[iBlock] != 0) && (nSize <= panBlockSize[iBlock]))
1342
0
    {
1343
0
        panBlockSize[iBlock] = nSize;
1344
        // fprintf( stderr, "Reusing block %d\n", iBlock );
1345
0
        return;
1346
0
    }
1347
1348
1.60k
    panBlockStart[iBlock] = HFAAllocateSpace(psInfo, nSize);
1349
1350
1.60k
    panBlockSize[iBlock] = nSize;
1351
1352
    // Need to rewrite this info to the RasterDMS node.
1353
1.60k
    HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1354
1355
1.60k
    if (!poDMS)
1356
0
    {
1357
0
        CPLError(CE_Failure, CPLE_FileIO, "Unable to load RasterDMS");
1358
0
        return;
1359
0
    }
1360
1361
1.60k
    char szVarName[64];
1362
1.60k
    snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].offset", iBlock);
1363
1.60k
    poDMS->SetIntField(szVarName, static_cast<int>(panBlockStart[iBlock]));
1364
1365
1.60k
    snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].size", iBlock);
1366
1.60k
    poDMS->SetIntField(szVarName, panBlockSize[iBlock]);
1367
1.60k
}
1368
1369
/************************************************************************/
1370
/*                           SetRasterBlock()                           */
1371
/************************************************************************/
1372
1373
CPLErr HFABand::SetRasterBlock(int nXBlock, int nYBlock, void *pData)
1374
1375
20.1k
{
1376
20.1k
    if (psInfo->eAccess == HFA_ReadOnly)
1377
0
    {
1378
0
        CPLError(CE_Failure, CPLE_NoWriteAccess,
1379
0
                 "Attempt to write block to read-only HFA file failed.");
1380
0
        return CE_Failure;
1381
0
    }
1382
1383
20.1k
    if (LoadBlockInfo() != CE_None)
1384
0
        return CE_Failure;
1385
1386
20.1k
    const int iBlock = nXBlock + nYBlock * nBlocksPerRow;
1387
1388
    // For now we don't support write invalid uncompressed blocks.
1389
    // To do so we will need logic to make space at the end of the
1390
    // file in the right size.
1391
20.1k
    if ((panBlockFlag[iBlock] & BFLG_VALID) == 0 &&
1392
20.1k
        !(panBlockFlag[iBlock] & BFLG_COMPRESSED) && panBlockStart[iBlock] == 0)
1393
0
    {
1394
0
        CPLError(CE_Failure, CPLE_AppDefined,
1395
0
                 "Attempt to write to invalid tile with number %d "
1396
0
                 "(X position %d, Y position %d).  This operation is "
1397
0
                 "currently unsupported by HFABand::SetRasterBlock().",
1398
0
                 iBlock, nXBlock, nYBlock);
1399
1400
0
        return CE_Failure;
1401
0
    }
1402
1403
    // Move to the location that the data sits.
1404
20.1k
    VSILFILE *fpData = nullptr;
1405
20.1k
    vsi_l_offset nBlockOffset = 0;
1406
1407
    // Calculate block offset in case we have spill file. Use predefined
1408
    // block map otherwise.
1409
20.1k
    if (fpExternal)
1410
0
    {
1411
0
        fpData = fpExternal;
1412
0
        nBlockOffset = nBlockStart + nBlockSize * iBlock * nLayerStackCount +
1413
0
                       nLayerStackIndex * nBlockSize;
1414
0
    }
1415
20.1k
    else
1416
20.1k
    {
1417
20.1k
        fpData = psInfo->fp;
1418
20.1k
        nBlockOffset = panBlockStart[iBlock];
1419
20.1k
        nBlockSize = panBlockSize[iBlock];
1420
20.1k
    }
1421
1422
    // Compressed Tile Handling.
1423
20.1k
    if (panBlockFlag[iBlock] & BFLG_COMPRESSED)
1424
1.60k
    {
1425
        // Write compressed data.
1426
1.60k
        int nInBlockSize = static_cast<int>(
1427
1.60k
            (static_cast<GIntBig>(nBlockXSize) * nBlockYSize *
1428
1.60k
                 static_cast<GIntBig>(HFAGetDataTypeBits(eDataType)) +
1429
1.60k
             7) /
1430
1.60k
            8);
1431
1432
        // Create the compressor object.
1433
1.60k
        HFACompress compress(pData, nInBlockSize, eDataType);
1434
1.60k
        if (compress.getCounts() == nullptr || compress.getValues() == nullptr)
1435
0
        {
1436
0
            return CE_Failure;
1437
0
        }
1438
1439
        // Compress the data.
1440
1.60k
        if (compress.compressBlock())
1441
1.60k
        {
1442
            // Get the data out of the object.
1443
1.60k
            GByte *pCounts = compress.getCounts();
1444
1.60k
            GUInt32 nSizeCount = compress.getCountSize();
1445
1.60k
            GByte *pValues = compress.getValues();
1446
1.60k
            GUInt32 nSizeValues = compress.getValueSize();
1447
1.60k
            GUInt32 nMin = compress.getMin();
1448
1.60k
            GUInt32 nNumRuns = compress.getNumRuns();
1449
1.60k
            GByte nNumBits = compress.getNumBits();
1450
1451
            // Compensate for the header info.
1452
1.60k
            GUInt32 nDataOffset = nSizeCount + 13;
1453
1.60k
            int nTotalSize = nSizeCount + nSizeValues + 13;
1454
1455
            // Allocate space for the compressed block and seek to it.
1456
1.60k
            ReAllocBlock(iBlock, nTotalSize);
1457
1458
1.60k
            nBlockOffset = panBlockStart[iBlock];
1459
1.60k
            nBlockSize = panBlockSize[iBlock];
1460
1461
            // Seek to offset.
1462
1.60k
            if (VSIFSeekL(fpData, nBlockOffset, SEEK_SET) != 0)
1463
0
            {
1464
0
                CPLError(CE_Failure, CPLE_FileIO,
1465
0
                         "Seek to %x:%08x on %p failed\n%s",
1466
0
                         static_cast<int>(nBlockOffset >> 32),
1467
0
                         static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1468
0
                         VSIStrerror(errno));
1469
0
                return CE_Failure;
1470
0
            }
1471
1472
            // Byte swap to local byte order if required.  It appears that
1473
            // raster data is always stored in Intel byte order in Imagine
1474
            // files.
1475
1476
#ifdef CPL_MSB
1477
            CPL_SWAP32PTR(&nMin);
1478
            CPL_SWAP32PTR(&nNumRuns);
1479
            CPL_SWAP32PTR(&nDataOffset);
1480
#endif  // def CPL_MSB
1481
1482
            // Write out the Minimum value.
1483
1.60k
            bool bRet = VSIFWriteL(&nMin, sizeof(nMin), 1, fpData) > 0;
1484
1485
            // The number of runs.
1486
1.60k
            bRet &= VSIFWriteL(&nNumRuns, sizeof(nNumRuns), 1, fpData) > 0;
1487
1488
            // The offset to the data.
1489
1.60k
            bRet &=
1490
1.60k
                VSIFWriteL(&nDataOffset, sizeof(nDataOffset), 1, fpData) > 0;
1491
1492
            // The number of bits.
1493
1.60k
            bRet &= VSIFWriteL(&nNumBits, sizeof(nNumBits), 1, fpData) > 0;
1494
1495
            // The counters - MSB stuff handled in HFACompress.
1496
1.60k
            bRet &= VSIFWriteL(pCounts, nSizeCount, 1, fpData) > 0;
1497
1498
            // The values - MSB stuff handled in HFACompress.
1499
1.60k
            bRet &= VSIFWriteL(pValues, nSizeValues, 1, fpData) > 0;
1500
1501
1.60k
            if (!bRet)
1502
0
                return CE_Failure;
1503
1504
            // Compressed data is freed in the HFACompress destructor.
1505
1.60k
        }
1506
0
        else
1507
0
        {
1508
            // If we have actually made the block bigger - i.e. does not
1509
            // compress well.
1510
0
            panBlockFlag[iBlock] ^= BFLG_COMPRESSED;
1511
            // Alloc more space for the uncompressed block.
1512
0
            ReAllocBlock(iBlock, nInBlockSize);
1513
1514
0
            nBlockOffset = panBlockStart[iBlock];
1515
0
            nBlockSize = panBlockSize[iBlock];
1516
1517
            // Need to change the RasterDMS entry.
1518
0
            HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1519
1520
0
            if (!poDMS)
1521
0
            {
1522
0
                CPLError(CE_Failure, CPLE_FileIO, "Unable to load RasterDMS");
1523
0
                return CE_Failure;
1524
0
            }
1525
1526
0
            char szVarName[64] = {};
1527
0
            snprintf(szVarName, sizeof(szVarName),
1528
0
                     "blockinfo[%d].compressionType", iBlock);
1529
0
            poDMS->SetIntField(szVarName, 0);
1530
0
        }
1531
1532
        // If the block was previously invalid, mark it as valid now.
1533
1.60k
        if ((panBlockFlag[iBlock] & BFLG_VALID) == 0)
1534
1.60k
        {
1535
1.60k
            char szVarName[64];
1536
1.60k
            HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1537
1538
1.60k
            if (!poDMS)
1539
0
            {
1540
0
                CPLError(CE_Failure, CPLE_FileIO, "Unable to load RasterDMS");
1541
0
                return CE_Failure;
1542
0
            }
1543
1544
1.60k
            snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].logvalid",
1545
1.60k
                     iBlock);
1546
1.60k
            poDMS->SetStringField(szVarName, "true");
1547
1548
1.60k
            panBlockFlag[iBlock] |= BFLG_VALID;
1549
1.60k
        }
1550
1.60k
    }
1551
1552
    // Uncompressed TILE handling.
1553
20.1k
    if ((panBlockFlag[iBlock] & BFLG_COMPRESSED) == 0)
1554
18.5k
    {
1555
1556
18.5k
        if (VSIFSeekL(fpData, nBlockOffset, SEEK_SET) != 0)
1557
0
        {
1558
0
            CPLError(CE_Failure, CPLE_FileIO,
1559
0
                     "Seek to %x:%08x on %p failed\n%s",
1560
0
                     static_cast<int>(nBlockOffset >> 32),
1561
0
                     static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1562
0
                     VSIStrerror(errno));
1563
0
            return CE_Failure;
1564
0
        }
1565
1566
        // Byte swap to local byte order if required.  It appears that
1567
        // raster data is always stored in Intel byte order in Imagine
1568
        // files.
1569
1570
#ifdef CPL_MSB
1571
        if (HFAGetDataTypeBits(eDataType) == 16)
1572
        {
1573
            for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1574
                CPL_SWAP16PTR(((unsigned char *)pData) + ii * 2);
1575
        }
1576
        else if (HFAGetDataTypeBits(eDataType) == 32)
1577
        {
1578
            for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1579
                CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1580
        }
1581
        else if (eDataType == EPT_f64)
1582
        {
1583
            for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1584
                CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1585
        }
1586
        else if (eDataType == EPT_c64)
1587
        {
1588
            for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1589
                CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1590
        }
1591
        else if (eDataType == EPT_c128)
1592
        {
1593
            for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1594
                CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1595
        }
1596
#endif  // def CPL_MSB
1597
1598
        // Write uncompressed data.
1599
18.5k
        if (VSIFWriteL(pData, static_cast<size_t>(nBlockSize), 1, fpData) != 1)
1600
0
        {
1601
0
            CPLError(CE_Failure, CPLE_FileIO,
1602
0
                     "Write of %d bytes at %x:%08x on %p failed.\n%s",
1603
0
                     static_cast<int>(nBlockSize),
1604
0
                     static_cast<int>(nBlockOffset >> 32),
1605
0
                     static_cast<int>(nBlockOffset & 0xffffffff), fpData,
1606
0
                     VSIStrerror(errno));
1607
0
            return CE_Failure;
1608
0
        }
1609
1610
        // If the block was previously invalid, mark it as valid now.
1611
18.5k
        if ((panBlockFlag[iBlock] & BFLG_VALID) == 0)
1612
18.5k
        {
1613
18.5k
            char szVarName[64];
1614
18.5k
            HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
1615
18.5k
            if (poDMS == nullptr)
1616
0
            {
1617
0
                CPLError(CE_Failure, CPLE_AppDefined,
1618
0
                         "Unable to get RasterDMS when trying to mark "
1619
0
                         "block valid.");
1620
0
                return CE_Failure;
1621
0
            }
1622
18.5k
            snprintf(szVarName, sizeof(szVarName), "blockinfo[%d].logvalid",
1623
18.5k
                     iBlock);
1624
18.5k
            poDMS->SetStringField(szVarName, "true");
1625
1626
18.5k
            panBlockFlag[iBlock] |= BFLG_VALID;
1627
18.5k
        }
1628
18.5k
    }
1629
    // Swap back, since we don't really have permission to change
1630
    // the callers buffer.
1631
1632
#ifdef CPL_MSB
1633
    if (HFAGetDataTypeBits(eDataType) == 16)
1634
    {
1635
        for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1636
            CPL_SWAP16PTR(((unsigned char *)pData) + ii * 2);
1637
    }
1638
    else if (HFAGetDataTypeBits(eDataType) == 32)
1639
    {
1640
        for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1641
            CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1642
    }
1643
    else if (eDataType == EPT_f64)
1644
    {
1645
        for (int ii = 0; ii < nBlockXSize * nBlockYSize; ii++)
1646
            CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1647
    }
1648
    else if (eDataType == EPT_c64)
1649
    {
1650
        for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1651
            CPL_SWAP32PTR(((unsigned char *)pData) + ii * 4);
1652
    }
1653
    else if (eDataType == EPT_c128)
1654
    {
1655
        for (int ii = 0; ii < nBlockXSize * nBlockYSize * 2; ii++)
1656
            CPL_SWAP64PTR(((unsigned char *)pData) + ii * 8);
1657
    }
1658
#endif  // def CPL_MSB
1659
1660
20.1k
    return CE_None;
1661
20.1k
}
1662
1663
/************************************************************************/
1664
/*                         GetBandName()                                */
1665
/*                                                                      */
1666
/*      Return the Layer Name                                           */
1667
/************************************************************************/
1668
1669
const char *HFABand::GetBandName()
1670
27.6k
{
1671
27.6k
    if (strlen(poNode->GetName()) > 0)
1672
27.6k
        return poNode->GetName();
1673
1674
0
    for (int iBand = 0; iBand < psInfo->nBands; iBand++)
1675
0
    {
1676
0
        if (psInfo->papoBand[iBand] == this)
1677
0
        {
1678
0
            osOverName.Printf("Layer_%d", iBand + 1);
1679
0
            return osOverName;
1680
0
        }
1681
0
    }
1682
1683
0
    osOverName.Printf("Layer_%x", poNode->GetFilePos());
1684
0
    return osOverName;
1685
0
}
1686
1687
/************************************************************************/
1688
/*                         SetBandName()                                */
1689
/*                                                                      */
1690
/*      Set the Layer Name                                              */
1691
/************************************************************************/
1692
1693
void HFABand::SetBandName(const char *pszName)
1694
2.43k
{
1695
2.43k
    if (psInfo->eAccess == HFA_Update)
1696
2.43k
    {
1697
2.43k
        poNode->SetName(pszName);
1698
2.43k
    }
1699
2.43k
}
1700
1701
/************************************************************************/
1702
/*                         SetNoDataValue()                             */
1703
/*                                                                      */
1704
/*      Set the band no-data value                                      */
1705
/************************************************************************/
1706
1707
CPLErr HFABand::SetNoDataValue(double dfValue)
1708
7.37k
{
1709
7.37k
    if (psInfo->eAccess != HFA_Update)
1710
0
        return CE_Failure;
1711
1712
7.37k
    HFAEntry *poNDNode = poNode->GetNamedChild("Eimg_NonInitializedValue");
1713
1714
7.37k
    if (poNDNode == nullptr)
1715
7.37k
    {
1716
7.37k
        poNDNode = HFAEntry::New(psInfo, "Eimg_NonInitializedValue",
1717
7.37k
                                 "Eimg_NonInitializedValue", poNode);
1718
7.37k
    }
1719
1720
7.37k
    poNDNode->MakeData(8 + 12 + 8);
1721
7.37k
    poNDNode->SetPosition();
1722
1723
7.37k
    poNDNode->SetIntField("valueBD[-3]", EPT_f64);
1724
7.37k
    poNDNode->SetIntField("valueBD[-2]", 1);
1725
7.37k
    poNDNode->SetIntField("valueBD[-1]", 1);
1726
1727
7.37k
    if (poNDNode->SetDoubleField("valueBD[0]", dfValue) == CE_Failure)
1728
0
        return CE_Failure;
1729
1730
7.37k
    bNoDataSet = true;
1731
7.37k
    dfNoData = dfValue;
1732
7.37k
    return CE_None;
1733
7.37k
}
1734
1735
/************************************************************************/
1736
/*                        HFAReadBFUniqueBins()                         */
1737
/*                                                                      */
1738
/*      Attempt to read the bins used for a PCT or RAT from a           */
1739
/*      BinFunction node.  On failure just return NULL.                 */
1740
/************************************************************************/
1741
1742
double *HFAReadBFUniqueBins(HFAEntry *poBinFunc, int nPCTColors)
1743
1744
133
{
1745
    // First confirm this is a "BFUnique" bin function.  We don't
1746
    // know what to do with any other types.
1747
133
    const char *pszBinFunctionType =
1748
133
        poBinFunc->GetStringField("binFunction.type.string");
1749
1750
133
    if (pszBinFunctionType == nullptr || !EQUAL(pszBinFunctionType, "BFUnique"))
1751
11
        return nullptr;
1752
1753
    // Process dictionary.
1754
122
    const char *pszDict =
1755
122
        poBinFunc->GetStringField("binFunction.MIFDictionary.string");
1756
122
    if (pszDict == nullptr)
1757
3
        pszDict = poBinFunc->GetStringField("binFunction.MIFDictionary");
1758
122
    if (pszDict == nullptr)
1759
3
        return nullptr;
1760
1761
119
    HFADictionary oMiniDict(pszDict);
1762
1763
119
    HFAType *poBFUnique = oMiniDict.FindType("BFUnique");
1764
119
    if (poBFUnique == nullptr)
1765
34
        return nullptr;
1766
1767
    // Field the MIFObject raw data pointer.
1768
85
    int nMIFObjectSize = 0;
1769
85
    const GByte *pabyMIFObject =
1770
85
        reinterpret_cast<const GByte *>(poBinFunc->GetStringField(
1771
85
            "binFunction.MIFObject", nullptr, &nMIFObjectSize));
1772
1773
85
    if (pabyMIFObject == nullptr ||
1774
81
        nMIFObjectSize < 24 + static_cast<int>(sizeof(double)) * nPCTColors)
1775
7
        return nullptr;
1776
1777
    // Confirm that this is a 64bit floating point basearray.
1778
78
    if (pabyMIFObject[20] != 0x0a || pabyMIFObject[21] != 0x00)
1779
6
    {
1780
6
        CPLDebug("HFA", "HFAReadPCTBins(): "
1781
6
                        "The basedata does not appear to be EGDA_TYPE_F64.");
1782
6
        return nullptr;
1783
6
    }
1784
1785
    // Decode bins.
1786
72
    double *padfBins =
1787
72
        static_cast<double *>(CPLCalloc(sizeof(double), nPCTColors));
1788
1789
72
    memcpy(padfBins, pabyMIFObject + 24, sizeof(double) * nPCTColors);
1790
1791
6.35k
    for (int i = 0; i < nPCTColors; i++)
1792
6.28k
    {
1793
6.28k
        HFAStandard(8, padfBins + i);
1794
#if DEBUG_VERBOSE
1795
        CPLDebug("HFA", "Bin[%d] = %g", i, padfBins[i]);
1796
#endif
1797
6.28k
    }
1798
1799
72
    return padfBins;
1800
78
}
1801
1802
/************************************************************************/
1803
/*                               GetPCT()                               */
1804
/*                                                                      */
1805
/*      Return PCT information, if any exists.                          */
1806
/************************************************************************/
1807
1808
CPLErr HFABand::GetPCT(int *pnColors, double **ppadfRed, double **ppadfGreen,
1809
                       double **ppadfBlue, double **ppadfAlpha,
1810
                       double **ppadfBins)
1811
1812
21.1k
{
1813
21.1k
    *pnColors = 0;
1814
21.1k
    *ppadfRed = nullptr;
1815
21.1k
    *ppadfGreen = nullptr;
1816
21.1k
    *ppadfBlue = nullptr;
1817
21.1k
    *ppadfAlpha = nullptr;
1818
21.1k
    *ppadfBins = nullptr;
1819
1820
    // If we haven't already tried to load the colors, do so now.
1821
21.1k
    if (nPCTColors == -1)
1822
21.1k
    {
1823
1824
21.1k
        nPCTColors = 0;
1825
1826
21.1k
        HFAEntry *poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Red");
1827
21.1k
        if (poColumnEntry == nullptr)
1828
20.8k
            return CE_Failure;
1829
1830
262
        nPCTColors = poColumnEntry->GetIntField("numRows");
1831
262
        if (nPCTColors < 0 || nPCTColors > 65536)
1832
39
        {
1833
39
            CPLError(CE_Failure, CPLE_AppDefined,
1834
39
                     "Invalid number of colors: %d", nPCTColors);
1835
39
            return CE_Failure;
1836
39
        }
1837
1838
792
        for (int iColumn = 0; iColumn < 4; iColumn++)
1839
651
        {
1840
651
            apadfPCT[iColumn] = static_cast<double *>(
1841
651
                VSI_MALLOC2_VERBOSE(sizeof(double), nPCTColors));
1842
651
            if (apadfPCT[iColumn] == nullptr)
1843
46
            {
1844
46
                return CE_Failure;
1845
46
            }
1846
1847
605
            if (iColumn == 0)
1848
177
            {
1849
177
                poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Red");
1850
177
            }
1851
428
            else if (iColumn == 1)
1852
145
            {
1853
145
                poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Green");
1854
145
            }
1855
283
            else if (iColumn == 2)
1856
142
            {
1857
142
                poColumnEntry = poNode->GetNamedChild("Descriptor_Table.Blue");
1858
142
            }
1859
141
            else if (iColumn == 3)
1860
141
            {
1861
141
                poColumnEntry =
1862
141
                    poNode->GetNamedChild("Descriptor_Table.Opacity");
1863
141
            }
1864
1865
605
            if (poColumnEntry == nullptr)
1866
186
            {
1867
186
                double *pdCol = apadfPCT[iColumn];
1868
193k
                for (int i = 0; i < nPCTColors; i++)
1869
193k
                    pdCol[i] = 1.0;
1870
186
            }
1871
419
            else
1872
419
            {
1873
419
                if (VSIFSeekL(psInfo->fp,
1874
419
                              poColumnEntry->GetIntField("columnDataPtr"),
1875
419
                              SEEK_SET) < 0)
1876
1
                {
1877
1
                    CPLError(CE_Failure, CPLE_FileIO,
1878
1
                             "VSIFSeekL() failed in HFABand::GetPCT().");
1879
1
                    return CE_Failure;
1880
1
                }
1881
418
                if (VSIFReadL(apadfPCT[iColumn], sizeof(double), nPCTColors,
1882
418
                              psInfo->fp) != static_cast<size_t>(nPCTColors))
1883
35
                {
1884
35
                    CPLError(CE_Failure, CPLE_FileIO,
1885
35
                             "VSIFReadL() failed in HFABand::GetPCT().");
1886
35
                    return CE_Failure;
1887
35
                }
1888
1889
177k
                for (int i = 0; i < nPCTColors; i++)
1890
177k
                    HFAStandard(8, apadfPCT[iColumn] + i);
1891
383
            }
1892
605
        }
1893
1894
        // Do we have a custom binning function? If so, try reading it.
1895
141
        HFAEntry *poBinFunc =
1896
141
            poNode->GetNamedChild("Descriptor_Table.#Bin_Function840#");
1897
1898
141
        if (poBinFunc != nullptr)
1899
64
        {
1900
64
            padfPCTBins = HFAReadBFUniqueBins(poBinFunc, nPCTColors);
1901
64
        }
1902
141
    }
1903
1904
    // Return the values.
1905
141
    if (nPCTColors == 0)
1906
0
        return CE_Failure;
1907
1908
141
    *pnColors = nPCTColors;
1909
141
    *ppadfRed = apadfPCT[0];
1910
141
    *ppadfGreen = apadfPCT[1];
1911
141
    *ppadfBlue = apadfPCT[2];
1912
141
    *ppadfAlpha = apadfPCT[3];
1913
141
    *ppadfBins = padfPCTBins;
1914
1915
141
    return CE_None;
1916
141
}
1917
1918
/************************************************************************/
1919
/*                               SetPCT()                               */
1920
/*                                                                      */
1921
/*      Set the PCT information for this band.                          */
1922
/************************************************************************/
1923
1924
CPLErr HFABand::SetPCT(int nColors, const double *padfRed,
1925
                       const double *padfGreen, const double *padfBlue,
1926
                       const double *padfAlpha)
1927
1928
263
{
1929
263
    static const char *const apszColNames[4] = {"Red", "Green", "Blue",
1930
263
                                                "Opacity"};
1931
263
    const double *const apadfValues[] = {padfRed, padfGreen, padfBlue,
1932
263
                                         padfAlpha};
1933
263
    HFAEntry *poEdsc_Table;
1934
1935
    // Do we need to try and clear any existing color table?
1936
263
    if (nColors == 0)
1937
0
    {
1938
0
        poEdsc_Table = poNode->GetNamedChild("Descriptor_Table");
1939
0
        if (poEdsc_Table == nullptr)
1940
0
            return CE_None;
1941
1942
0
        for (int iColumn = 0; iColumn < 4; iColumn++)
1943
0
        {
1944
0
            HFAEntry *poEdsc_Column =
1945
0
                poEdsc_Table->GetNamedChild(apszColNames[iColumn]);
1946
0
            if (poEdsc_Column)
1947
0
                poEdsc_Column->RemoveAndDestroy();
1948
0
        }
1949
1950
0
        return CE_None;
1951
0
    }
1952
1953
    // Create the Descriptor table.
1954
263
    poEdsc_Table = poNode->GetNamedChild("Descriptor_Table");
1955
263
    if (poEdsc_Table == nullptr ||
1956
0
        !EQUAL(poEdsc_Table->GetType(), "Edsc_Table"))
1957
263
        poEdsc_Table =
1958
263
            HFAEntry::New(psInfo, "Descriptor_Table", "Edsc_Table", poNode);
1959
1960
263
    poEdsc_Table->SetIntField("numrows", nColors);
1961
1962
    // Create the Binning function node.  I am not sure that we
1963
    // really need this though.
1964
263
    HFAEntry *poEdsc_BinFunction =
1965
263
        poEdsc_Table->GetNamedChild("#Bin_Function#");
1966
263
    if (poEdsc_BinFunction == nullptr ||
1967
0
        !EQUAL(poEdsc_BinFunction->GetType(), "Edsc_BinFunction"))
1968
263
        poEdsc_BinFunction = HFAEntry::New(psInfo, "#Bin_Function#",
1969
263
                                           "Edsc_BinFunction", poEdsc_Table);
1970
1971
    // Because of the BaseData we have to hardcode the size.
1972
263
    poEdsc_BinFunction->MakeData(30);
1973
1974
263
    poEdsc_BinFunction->SetIntField("numBins", nColors);
1975
263
    poEdsc_BinFunction->SetStringField("binFunction", "direct");
1976
263
    poEdsc_BinFunction->SetDoubleField("minLimit", 0.0);
1977
263
    poEdsc_BinFunction->SetDoubleField("maxLimit", nColors - 1.0);
1978
1979
    // Process each color component.
1980
1.31k
    for (int iColumn = 0; iColumn < 4; iColumn++)
1981
1.05k
    {
1982
1.05k
        const double *padfValues = apadfValues[iColumn];
1983
1.05k
        const char *pszName = apszColNames[iColumn];
1984
1985
        // Create the Edsc_Column.
1986
1.05k
        HFAEntry *poEdsc_Column = poEdsc_Table->GetNamedChild(pszName);
1987
1.05k
        if (poEdsc_Column == nullptr ||
1988
0
            !EQUAL(poEdsc_Column->GetType(), "Edsc_Column"))
1989
1.05k
            poEdsc_Column =
1990
1.05k
                HFAEntry::New(psInfo, pszName, "Edsc_Column", poEdsc_Table);
1991
1992
1.05k
        poEdsc_Column->SetIntField("numRows", nColors);
1993
1.05k
        poEdsc_Column->SetStringField("dataType", "real");
1994
1.05k
        poEdsc_Column->SetIntField("maxNumChars", 0);
1995
1996
        // Write the data out.
1997
1.05k
        const auto nOffset = HFAAllocateSpace(psInfo, 8 * nColors);
1998
1.05k
        if (nOffset > static_cast<unsigned>(INT_MAX))
1999
0
            return CE_Failure;
2000
2001
1.05k
        poEdsc_Column->SetIntField("columnDataPtr", static_cast<int>(nOffset));
2002
2003
1.05k
        double *padfFileData =
2004
1.05k
            static_cast<double *>(CPLMalloc(nColors * sizeof(double)));
2005
3.17k
        for (int iColor = 0; iColor < nColors; iColor++)
2006
2.12k
        {
2007
2.12k
            padfFileData[iColor] = padfValues[iColor];
2008
2.12k
            HFAStandard(8, padfFileData + iColor);
2009
2.12k
        }
2010
1.05k
        const bool bRet = VSIFSeekL(psInfo->fp, nOffset, SEEK_SET) >= 0 &&
2011
1.05k
                          VSIFWriteL(padfFileData, 8, nColors, psInfo->fp) ==
2012
1.05k
                              static_cast<size_t>(nColors);
2013
1.05k
        CPLFree(padfFileData);
2014
1.05k
        if (!bRet)
2015
0
            return CE_Failure;
2016
1.05k
    }
2017
2018
    // Update the layer type to be thematic.
2019
263
    poNode->SetStringField("layerType", "thematic");
2020
2021
263
    return CE_None;
2022
263
}
2023
2024
/************************************************************************/
2025
/*                      HFAGetOverviewBlockSize()                       */
2026
/************************************************************************/
2027
2028
static int HFAGetOverviewBlockSize()
2029
0
{
2030
0
    const char *pszVal = CPLGetConfigOption("GDAL_HFA_OVR_BLOCKSIZE", "64");
2031
0
    int nOvrBlockSize = atoi(pszVal);
2032
0
    if (nOvrBlockSize < 32 || nOvrBlockSize > 2048 ||
2033
0
        !CPLIsPowerOfTwo(nOvrBlockSize))
2034
0
    {
2035
0
        CPLErrorOnce(CE_Warning, CPLE_NotSupported,
2036
0
                     "Wrong value for GDAL_HFA_OVR_BLOCKSIZE : %s. "
2037
0
                     "Should be a power of 2 between 32 and 2048. "
2038
0
                     "Defaulting to 64",
2039
0
                     pszVal);
2040
0
        nOvrBlockSize = 64;
2041
0
    }
2042
2043
0
    return nOvrBlockSize;
2044
0
}
2045
2046
/************************************************************************/
2047
/*                           CreateOverview()                           */
2048
/************************************************************************/
2049
2050
int HFABand::CreateOverview(int nOverviewLevel, const char *pszResampling)
2051
2052
0
{
2053
0
    const int nOXSize = DIV_ROUND_UP(psInfo->nXSize, nOverviewLevel);
2054
0
    const int nOYSize = DIV_ROUND_UP(psInfo->nYSize, nOverviewLevel);
2055
2056
    // Do we want to use a dependent file (.rrd) for the overviews?
2057
    // Or just create them directly in this file?
2058
0
    HFAInfo_t *psRRDInfo = psInfo;
2059
0
    HFAEntry *poParent = poNode;
2060
2061
0
    if (CPLTestBool(CPLGetConfigOption("HFA_USE_RRD", "NO")))
2062
0
    {
2063
0
        psRRDInfo = HFACreateDependent(psInfo);
2064
0
        if (psRRDInfo == nullptr)
2065
0
            return -1;
2066
2067
0
        poParent = psRRDInfo->poRoot->GetNamedChild(GetBandName());
2068
2069
        // Need to create layer object.
2070
0
        if (poParent == nullptr)
2071
0
        {
2072
0
            poParent = HFAEntry::New(psRRDInfo, GetBandName(), "Eimg_Layer",
2073
0
                                     psRRDInfo->poRoot);
2074
0
        }
2075
0
    }
2076
2077
    // What pixel type should we use for the overview.  Usually
2078
    // this is the same as the base layer, but when
2079
    // AVERAGE_BIT2GRAYSCALE is in effect we force it to u8 from u1.
2080
0
    EPTType eOverviewDataType = eDataType;
2081
2082
0
    if (STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2GR"))
2083
0
        eOverviewDataType = EPT_u8;
2084
2085
    // Eventually we need to decide on the whether to use the spill
2086
    // file, primarily on the basis of whether the new overview
2087
    // will drive our .img file size near 4GB.  For now, just base
2088
    // it on the config options.
2089
0
    bool bCreateLargeRaster =
2090
0
        CPLTestBool(CPLGetConfigOption("USE_SPILL", "NO"));
2091
0
    GIntBig nValidFlagsOffset = 0;
2092
0
    GIntBig nDataOffset = 0;
2093
0
    int nOverviewBlockSize = HFAGetOverviewBlockSize();
2094
2095
0
    if ((psRRDInfo->nEndOfFile +
2096
0
         (nOXSize * static_cast<double>(nOYSize)) *
2097
0
             (HFAGetDataTypeBits(eOverviewDataType) / 8)) > 2000000000.0)
2098
0
        bCreateLargeRaster = true;
2099
2100
0
    if (bCreateLargeRaster)
2101
0
    {
2102
0
        if (!HFACreateSpillStack(psRRDInfo, nOXSize, nOYSize, 1,
2103
0
                                 nOverviewBlockSize, eOverviewDataType,
2104
0
                                 &nValidFlagsOffset, &nDataOffset))
2105
0
        {
2106
0
            return -1;
2107
0
        }
2108
0
    }
2109
2110
    // Are we compressed? If so, overview should be too (unless
2111
    // HFA_COMPRESS_OVR is defined).
2112
    // Check RasterDMS like HFAGetBandInfo.
2113
0
    bool bCompressionType = false;
2114
0
    const char *pszCompressOvr =
2115
0
        CPLGetConfigOption("HFA_COMPRESS_OVR", nullptr);
2116
0
    if (pszCompressOvr != nullptr)
2117
0
    {
2118
0
        bCompressionType = CPLTestBool(pszCompressOvr);
2119
0
    }
2120
0
    else
2121
0
    {
2122
0
        HFAEntry *poDMS = poNode->GetNamedChild("RasterDMS");
2123
2124
0
        if (poDMS != nullptr)
2125
0
            bCompressionType = poDMS->GetIntField("compressionType") != 0;
2126
0
    }
2127
2128
    // Create the layer.
2129
0
    CPLString osLayerName;
2130
0
    osLayerName.Printf("_ss_%d_", nOverviewLevel);
2131
2132
0
    if (!HFACreateLayer(
2133
0
            psRRDInfo, poParent, osLayerName, TRUE, nOverviewBlockSize,
2134
0
            bCompressionType, bCreateLargeRaster, FALSE, nOXSize, nOYSize,
2135
0
            eOverviewDataType, nullptr, nValidFlagsOffset, nDataOffset, 1, 0))
2136
0
        return -1;
2137
2138
0
    HFAEntry *poOverLayer = poParent->GetNamedChild(osLayerName);
2139
0
    if (poOverLayer == nullptr)
2140
0
        return -1;
2141
2142
    // Create RRDNamesList list if it does not yet exist.
2143
0
    HFAEntry *poRRDNamesList = poNode->GetNamedChild("RRDNamesList");
2144
0
    if (poRRDNamesList == nullptr)
2145
0
    {
2146
0
        poRRDNamesList =
2147
0
            HFAEntry::New(psInfo, "RRDNamesList", "Eimg_RRDNamesList", poNode);
2148
0
        poRRDNamesList->MakeData(23 + 16 + 8 + 3000);  // Hack for growth room.
2149
2150
        // We need to hardcode file offset into the data, so locate it now.
2151
0
        poRRDNamesList->SetPosition();
2152
2153
0
        poRRDNamesList->SetStringField("algorithm.string",
2154
0
                                       "IMAGINE 2X2 Resampling");
2155
0
    }
2156
2157
    // Add new overview layer to RRDNamesList.
2158
0
    int iNextName = poRRDNamesList->GetFieldCount("nameList");
2159
0
    char szName[50];
2160
0
    CPLString osNodeName;
2161
2162
0
    snprintf(szName, sizeof(szName), "nameList[%d].string", iNextName);
2163
2164
0
    osLayerName.Printf("%s(:%s:_ss_%d_)", psRRDInfo->pszFilename, GetBandName(),
2165
0
                       nOverviewLevel);
2166
2167
    // TODO: Need to add to end of array (that is pretty hard).
2168
0
    if (poRRDNamesList->SetStringField(szName, osLayerName) != CE_None)
2169
0
    {
2170
0
        poRRDNamesList->MakeData(poRRDNamesList->GetDataSize() + 3000);
2171
0
        if (poRRDNamesList->SetStringField(szName, osLayerName) != CE_None)
2172
0
            return -1;
2173
0
    }
2174
2175
    // Add to the list of overviews for this band.
2176
0
    papoOverviews = static_cast<HFABand **>(
2177
0
        CPLRealloc(papoOverviews, sizeof(void *) * ++nOverviews));
2178
0
    papoOverviews[nOverviews - 1] = new HFABand(psRRDInfo, poOverLayer);
2179
2180
    // If there is a nodata value, copy it to the overview band.
2181
0
    if (bNoDataSet)
2182
0
        papoOverviews[nOverviews - 1]->SetNoDataValue(dfNoData);
2183
2184
0
    return nOverviews - 1;
2185
0
}