Coverage Report

Created: 2025-06-09 07:07

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