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

Generated by: LCOV version 1.14