LCOV - code coverage report
Current view: top level - frmts/hfa - hfaband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 616 947 65.0 %
Date: 2026-05-28 11:29:44 Functions: 18 18 100.0 %

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

Generated by: LCOV version 1.14