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

Generated by: LCOV version 1.14