LCOV - code coverage report
Current view: top level - frmts/aigrid - aigopen.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 92 178 51.7 %
Date: 2024-11-21 22:18:42 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  Arc/Info Binary Grid Translator
       5             :  * Purpose:  Grid file access cover API for non-GDAL use.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Frank Warmerdam
      10             :  * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "aigrid.h"
      16             : 
      17             : #ifndef CPL_IGNORE_RET_VAL_INT_defined
      18             : #define CPL_IGNORE_RET_VAL_INT_defined
      19             : 
      20           3 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      21             : {
      22           3 : }
      23             : #endif
      24             : 
      25             : /************************************************************************/
      26             : /*                              AIGOpen()                               */
      27             : /************************************************************************/
      28             : 
      29           9 : AIGInfo_t *AIGOpen(const char *pszInputName, const char *pszAccess)
      30             : 
      31             : {
      32             :     AIGInfo_t *psInfo;
      33             :     char *pszCoverName;
      34             : 
      35             :     (void)pszAccess;
      36             : 
      37             :     /* -------------------------------------------------------------------- */
      38             :     /*      If the pass name ends in .adf assume a file within the          */
      39             :     /*      coverage has been selected, and strip that off the coverage     */
      40             :     /*      name.                                                           */
      41             :     /* -------------------------------------------------------------------- */
      42           9 :     pszCoverName = CPLStrdup(pszInputName);
      43           9 :     if (EQUAL(pszCoverName + strlen(pszCoverName) - 4, ".adf"))
      44             :     {
      45             :         int i;
      46             : 
      47           0 :         for (i = (int)strlen(pszCoverName) - 1; i > 0; i--)
      48             :         {
      49           0 :             if (pszCoverName[i] == '\\' || pszCoverName[i] == '/')
      50             :             {
      51           0 :                 pszCoverName[i] = '\0';
      52           0 :                 break;
      53             :             }
      54             :         }
      55             : 
      56           0 :         if (i == 0)
      57           0 :             strcpy(pszCoverName, ".");
      58             :     }
      59             : 
      60             :     /* -------------------------------------------------------------------- */
      61             :     /*      Allocate info structure.                                        */
      62             :     /* -------------------------------------------------------------------- */
      63           9 :     psInfo = (AIGInfo_t *)CPLCalloc(sizeof(AIGInfo_t), 1);
      64           9 :     psInfo->bHasWarned = FALSE;
      65           9 :     psInfo->nFailedOpenings = 0;
      66           9 :     psInfo->pszCoverName = pszCoverName;
      67             : 
      68             :     /* -------------------------------------------------------------------- */
      69             :     /*      Read the header file.                                           */
      70             :     /* -------------------------------------------------------------------- */
      71           9 :     if (AIGReadHeader(pszCoverName, psInfo) != CE_None)
      72             :     {
      73           0 :         CPLFree(pszCoverName);
      74           0 :         CPLFree(psInfo);
      75           0 :         return NULL;
      76             :     }
      77             : 
      78             :     /* -------------------------------------------------------------------- */
      79             :     /*      Read the extents.                                               */
      80             :     /* -------------------------------------------------------------------- */
      81           9 :     if (AIGReadBounds(pszCoverName, psInfo) != CE_None)
      82             :     {
      83           0 :         AIGClose(psInfo);
      84           0 :         return NULL;
      85             :     }
      86             : 
      87             :     /* -------------------------------------------------------------------- */
      88             :     /*      Compute the number of pixels and lines, and the number of       */
      89             :     /*      tile files.                                                     */
      90             :     /* -------------------------------------------------------------------- */
      91           9 :     if (psInfo->dfCellSizeX <= 0 || psInfo->dfCellSizeY <= 0)
      92             :     {
      93           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Illegal cell size : %f x %f",
      94             :                  psInfo->dfCellSizeX, psInfo->dfCellSizeY);
      95           0 :         AIGClose(psInfo);
      96           0 :         return NULL;
      97             :     }
      98             : 
      99           9 :     psInfo->nPixels =
     100           9 :         (int)((psInfo->dfURX - psInfo->dfLLX + 0.5 * psInfo->dfCellSizeX) /
     101           9 :               psInfo->dfCellSizeX);
     102           9 :     psInfo->nLines =
     103           9 :         (int)((psInfo->dfURY - psInfo->dfLLY + 0.5 * psInfo->dfCellSizeY) /
     104           9 :               psInfo->dfCellSizeY);
     105             : 
     106           9 :     if (psInfo->nPixels <= 0 || psInfo->nLines <= 0)
     107             :     {
     108           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     109             :                  "Invalid raster dimensions : %d x %d", psInfo->nPixels,
     110             :                  psInfo->nLines);
     111           0 :         AIGClose(psInfo);
     112           0 :         return NULL;
     113             :     }
     114             : 
     115           9 :     if (psInfo->nBlockXSize <= 0 || psInfo->nBlockYSize <= 0 ||
     116           9 :         psInfo->nBlocksPerRow <= 0 || psInfo->nBlocksPerColumn <= 0 ||
     117           9 :         psInfo->nBlockXSize > INT_MAX / psInfo->nBlocksPerRow ||
     118           9 :         psInfo->nBlockYSize > INT_MAX / psInfo->nBlocksPerColumn)
     119             :     {
     120           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     121             :                  "Invalid block characteristics: nBlockXSize=%d, "
     122             :                  "nBlockYSize=%d, nBlocksPerRow=%d, nBlocksPerColumn=%d",
     123             :                  psInfo->nBlockXSize, psInfo->nBlockYSize,
     124             :                  psInfo->nBlocksPerRow, psInfo->nBlocksPerColumn);
     125           0 :         AIGClose(psInfo);
     126           0 :         return NULL;
     127             :     }
     128             : 
     129           9 :     if (psInfo->nBlocksPerRow > INT_MAX / psInfo->nBlocksPerColumn)
     130             :     {
     131           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Too many blocks");
     132           0 :         AIGClose(psInfo);
     133           0 :         return NULL;
     134             :     }
     135             : 
     136           9 :     psInfo->nTileXSize = psInfo->nBlockXSize * psInfo->nBlocksPerRow;
     137           9 :     psInfo->nTileYSize = psInfo->nBlockYSize * psInfo->nBlocksPerColumn;
     138             : 
     139           9 :     psInfo->nTilesPerRow = (psInfo->nPixels - 1) / psInfo->nTileXSize + 1;
     140           9 :     psInfo->nTilesPerColumn = (psInfo->nLines - 1) / psInfo->nTileYSize + 1;
     141             : 
     142             :     /* Each tile map to a file and there are only 3 characters in the */
     143             :     /* filename for the X and Y components. */
     144           9 :     if (psInfo->nTilesPerRow > 1000 * 1000 / psInfo->nTilesPerColumn)
     145             :     {
     146           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Too many tiles");
     147           0 :         psInfo->nTilesPerRow = 0; /* to avoid int32 overflow in AIGClose() */
     148           0 :         psInfo->nTilesPerColumn = 0;
     149           0 :         AIGClose(psInfo);
     150           0 :         return NULL;
     151             :     }
     152             : 
     153             :     /* -------------------------------------------------------------------- */
     154             :     /*      Setup tile infos, but defer reading of tile data.               */
     155             :     /* -------------------------------------------------------------------- */
     156           9 :     psInfo->pasTileInfo = (AIGTileInfo *)VSI_CALLOC_VERBOSE(
     157             :         sizeof(AIGTileInfo),
     158             :         (size_t)psInfo->nTilesPerRow * psInfo->nTilesPerColumn);
     159           9 :     if (psInfo->pasTileInfo == NULL)
     160             :     {
     161           0 :         AIGClose(psInfo);
     162           0 :         return NULL;
     163             :     }
     164             : 
     165             :     /* -------------------------------------------------------------------- */
     166             :     /*      Read the statistics.                                            */
     167             :     /* -------------------------------------------------------------------- */
     168           9 :     if (AIGReadStatistics(pszCoverName, psInfo) != CE_None)
     169             :     {
     170           0 :         AIGClose(psInfo);
     171           0 :         return NULL;
     172             :     }
     173             : 
     174           9 :     return (psInfo);
     175             : }
     176             : 
     177             : /************************************************************************/
     178             : /*                           AIGAccessTile()                            */
     179             : /************************************************************************/
     180             : 
     181           4 : CPLErr AIGAccessTile(AIGInfo_t *psInfo, int iTileX, int iTileY)
     182             : 
     183             : {
     184             :     char szBasename[32];
     185             :     char *pszFilename;
     186             :     AIGTileInfo *psTInfo;
     187           4 :     const size_t nFilenameLen = strlen(psInfo->pszCoverName) + 40;
     188             : 
     189             :     /* -------------------------------------------------------------------- */
     190             :     /*      Identify our tile.                                              */
     191             :     /* -------------------------------------------------------------------- */
     192           4 :     if (iTileX < 0 || iTileX >= psInfo->nTilesPerRow || iTileY < 0 ||
     193           4 :         iTileY >= psInfo->nTilesPerColumn)
     194             :     {
     195           0 :         CPLAssert(FALSE);
     196             :         return CE_Failure;
     197             :     }
     198             : 
     199           4 :     psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
     200             : 
     201           4 :     if (psTInfo->fpGrid != NULL)
     202           1 :         return psTInfo->panBlockOffset != NULL ? CE_None : CE_Failure;
     203             : 
     204           3 :     if (psTInfo->bTriedToLoad)
     205           0 :         return CE_None;
     206             : 
     207             : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     208             :     /* After a significant number of failed openings, don't even try further */
     209             :     if (psInfo->nFailedOpenings == 1000)
     210             :         return CE_None;
     211             : #endif
     212             : 
     213             :     /* -------------------------------------------------------------------- */
     214             :     /*      Compute the basename.                                           */
     215             :     /* -------------------------------------------------------------------- */
     216           3 :     if (iTileY == 0)
     217           3 :         snprintf(szBasename, sizeof(szBasename), "w%03d001", iTileX + 1);
     218           0 :     else if (iTileY == 1)
     219           0 :         snprintf(szBasename, sizeof(szBasename), "w%03d000", iTileX + 1);
     220             :     else
     221           0 :         snprintf(szBasename, sizeof(szBasename), "z%03d%03d", iTileX + 1,
     222             :                  iTileY - 1);
     223             : 
     224             :     /* -------------------------------------------------------------------- */
     225             :     /*      Open the file w001001.adf file itself.                          */
     226             :     /* -------------------------------------------------------------------- */
     227           3 :     pszFilename = (char *)CPLMalloc(nFilenameLen);
     228           3 :     snprintf(pszFilename, nFilenameLen, "%s/%s.adf", psInfo->pszCoverName,
     229             :              szBasename);
     230             : 
     231           3 :     psTInfo->fpGrid = AIGLLOpen(pszFilename, "rb");
     232           3 :     psTInfo->bTriedToLoad = TRUE;
     233             : 
     234           3 :     if (psTInfo->fpGrid == NULL)
     235             :     {
     236           0 :         psInfo->nFailedOpenings++;
     237           0 :         if (psInfo->nFailedOpenings < 100)
     238             :         {
     239           0 :             CPLError(
     240             :                 CE_Warning, CPLE_OpenFailed,
     241             :                 "Failed to open grid file, assuming region is nodata:\n%s\n",
     242             :                 pszFilename);
     243             :         }
     244             : 
     245           0 :         CPLFree(pszFilename);
     246           0 :         return CE_Warning;
     247             :     }
     248             : 
     249           3 :     CPLFree(pszFilename);
     250           3 :     pszFilename = NULL;
     251             : 
     252             :     /* -------------------------------------------------------------------- */
     253             :     /*      Read the block index file.                                      */
     254             :     /* -------------------------------------------------------------------- */
     255           3 :     return AIGReadBlockIndex(psInfo, psTInfo, szBasename);
     256             : }
     257             : 
     258             : /************************************************************************/
     259             : /*                            AIGReadTile()                             */
     260             : /************************************************************************/
     261             : 
     262           4 : CPLErr AIGReadTile(AIGInfo_t *psInfo, int nBlockXOff, int nBlockYOff,
     263             :                    GInt32 *panData)
     264             : 
     265             : {
     266             :     int nBlockID;
     267             :     CPLErr eErr;
     268             :     int iTileX, iTileY;
     269             :     AIGTileInfo *psTInfo;
     270             : 
     271             :     /* -------------------------------------------------------------------- */
     272             :     /*      Compute our tile, and ensure it is accessible (open).  Then     */
     273             :     /*      reduce block x/y values to be the block within that tile.       */
     274             :     /* -------------------------------------------------------------------- */
     275           4 :     iTileX = nBlockXOff / psInfo->nBlocksPerRow;
     276           4 :     iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
     277             : 
     278           4 :     eErr = AIGAccessTile(psInfo, iTileX, iTileY);
     279           4 :     if (eErr == CE_Failure)
     280           2 :         return eErr;
     281             : 
     282           2 :     psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
     283             : 
     284           2 :     nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
     285           2 :     nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
     286             : 
     287             :     /* -------------------------------------------------------------------- */
     288             :     /*      Request for tile from a file which does not exist - treat as    */
     289             :     /*      all nodata.                                                     */
     290             :     /* -------------------------------------------------------------------- */
     291           2 :     if (psTInfo->fpGrid == NULL)
     292             :     {
     293             :         int i;
     294           0 :         for (i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i--)
     295           0 :             panData[i] = ESRI_GRID_NO_DATA;
     296           0 :         return CE_None;
     297             :     }
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      validate block id.                                              */
     301             :     /* -------------------------------------------------------------------- */
     302           2 :     nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
     303           2 :     if (nBlockID < 0 ||
     304           2 :         nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn)
     305             :     {
     306           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Illegal block requested.");
     307           0 :         return CE_Failure;
     308             :     }
     309             : 
     310           2 :     if (nBlockID >= psTInfo->nBlocks)
     311             :     {
     312             :         int i;
     313           0 :         CPLDebug("AIG",
     314             :                  "Request legal block, but from beyond end of block map.\n"
     315             :                  "Assuming all nodata.");
     316           0 :         for (i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i--)
     317           0 :             panData[i] = ESRI_GRID_NO_DATA;
     318           0 :         return CE_None;
     319             :     }
     320             : 
     321             :     /* -------------------------------------------------------------------- */
     322             :     /*      Read block.                                                     */
     323             :     /* -------------------------------------------------------------------- */
     324           2 :     eErr = AIGReadBlock(psTInfo->fpGrid, psTInfo->panBlockOffset[nBlockID],
     325           2 :                         psTInfo->panBlockSize[nBlockID], psInfo->nBlockXSize,
     326             :                         psInfo->nBlockYSize, panData, psInfo->nCellType,
     327             :                         psInfo->bCompressed);
     328             : 
     329             :     /* -------------------------------------------------------------------- */
     330             :     /*      Apply floating point post-processing.                           */
     331             :     /* -------------------------------------------------------------------- */
     332           2 :     if (eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_FLOAT)
     333             :     {
     334           0 :         float *pafData = (float *)panData;
     335           0 :         int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
     336             : 
     337           0 :         for (i = 0; i < nPixels; i++)
     338             :         {
     339           0 :             panData[i] = (int)pafData[i];
     340             :         }
     341             :     }
     342             : 
     343           2 :     return (eErr);
     344             : }
     345             : 
     346             : /************************************************************************/
     347             : /*                          AIGReadFloatTile()                          */
     348             : /************************************************************************/
     349             : 
     350           0 : CPLErr AIGReadFloatTile(AIGInfo_t *psInfo, int nBlockXOff, int nBlockYOff,
     351             :                         float *pafData)
     352             : 
     353             : {
     354             :     int nBlockID;
     355             :     CPLErr eErr;
     356             :     int iTileX, iTileY;
     357             :     AIGTileInfo *psTInfo;
     358             : 
     359             :     /* -------------------------------------------------------------------- */
     360             :     /*      Compute our tile, and ensure it is accessible (open).  Then     */
     361             :     /*      reduce block x/y values to be the block within that tile.       */
     362             :     /* -------------------------------------------------------------------- */
     363           0 :     iTileX = nBlockXOff / psInfo->nBlocksPerRow;
     364           0 :     iTileY = nBlockYOff / psInfo->nBlocksPerColumn;
     365             : 
     366           0 :     eErr = AIGAccessTile(psInfo, iTileX, iTileY);
     367           0 :     if (eErr == CE_Failure)
     368           0 :         return eErr;
     369             : 
     370           0 :     psTInfo = psInfo->pasTileInfo + iTileX + iTileY * psInfo->nTilesPerRow;
     371             : 
     372           0 :     nBlockXOff -= iTileX * psInfo->nBlocksPerRow;
     373           0 :     nBlockYOff -= iTileY * psInfo->nBlocksPerColumn;
     374             : 
     375             :     /* -------------------------------------------------------------------- */
     376             :     /*      Request for tile from a file which does not exist - treat as    */
     377             :     /*      all nodata.                                                     */
     378             :     /* -------------------------------------------------------------------- */
     379           0 :     if (psTInfo->fpGrid == NULL)
     380             :     {
     381             :         int i;
     382           0 :         for (i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i--)
     383           0 :             pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
     384           0 :         return CE_None;
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      validate block id.                                              */
     389             :     /* -------------------------------------------------------------------- */
     390           0 :     nBlockID = nBlockXOff + nBlockYOff * psInfo->nBlocksPerRow;
     391           0 :     if (nBlockID < 0 ||
     392           0 :         nBlockID >= psInfo->nBlocksPerRow * psInfo->nBlocksPerColumn)
     393             :     {
     394           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Illegal block requested.");
     395           0 :         return CE_Failure;
     396             :     }
     397             : 
     398           0 :     if (nBlockID >= psTInfo->nBlocks)
     399             :     {
     400             :         int i;
     401           0 :         CPLDebug("AIG",
     402             :                  "Request legal block, but from beyond end of block map.\n"
     403             :                  "Assuming all nodata.");
     404           0 :         for (i = psInfo->nBlockXSize * psInfo->nBlockYSize - 1; i >= 0; i--)
     405           0 :             pafData[i] = ESRI_GRID_FLOAT_NO_DATA;
     406           0 :         return CE_None;
     407             :     }
     408             : 
     409             :     /* -------------------------------------------------------------------- */
     410             :     /*      Read block.                                                     */
     411             :     /* -------------------------------------------------------------------- */
     412           0 :     eErr = AIGReadBlock(psTInfo->fpGrid, psTInfo->panBlockOffset[nBlockID],
     413           0 :                         psTInfo->panBlockSize[nBlockID], psInfo->nBlockXSize,
     414             :                         psInfo->nBlockYSize, (GInt32 *)pafData,
     415             :                         psInfo->nCellType, psInfo->bCompressed);
     416             : 
     417             :     /* -------------------------------------------------------------------- */
     418             :     /*      Perform integer post processing.                                */
     419             :     /* -------------------------------------------------------------------- */
     420           0 :     if (eErr == CE_None && psInfo->nCellType == AIG_CELLTYPE_INT)
     421             :     {
     422           0 :         GUInt32 *panData = (GUInt32 *)pafData;
     423           0 :         int i, nPixels = psInfo->nBlockXSize * psInfo->nBlockYSize;
     424             : 
     425           0 :         for (i = 0; i < nPixels; i++)
     426             :         {
     427           0 :             pafData[i] = (float)panData[i];
     428             :         }
     429             :     }
     430             : 
     431           0 :     return (eErr);
     432             : }
     433             : 
     434             : /************************************************************************/
     435             : /*                              AIGClose()                              */
     436             : /************************************************************************/
     437             : 
     438           9 : void AIGClose(AIGInfo_t *psInfo)
     439             : 
     440             : {
     441           9 :     if (psInfo->pasTileInfo != NULL)
     442             :     {
     443           9 :         int nTileCount = psInfo->nTilesPerRow * psInfo->nTilesPerColumn;
     444             :         int iTile;
     445             : 
     446          18 :         for (iTile = 0; iTile < nTileCount; iTile++)
     447             :         {
     448           9 :             if (psInfo->pasTileInfo[iTile].fpGrid)
     449             :             {
     450           3 :                 CPL_IGNORE_RET_VAL_INT(
     451           3 :                     VSIFCloseL(psInfo->pasTileInfo[iTile].fpGrid));
     452             : 
     453           3 :                 CPLFree(psInfo->pasTileInfo[iTile].panBlockOffset);
     454           3 :                 CPLFree(psInfo->pasTileInfo[iTile].panBlockSize);
     455             :             }
     456             :         }
     457             :     }
     458             : 
     459           9 :     CPLFree(psInfo->pasTileInfo);
     460           9 :     CPLFree(psInfo->pszCoverName);
     461           9 :     CPLFree(psInfo);
     462           9 : }
     463             : 
     464             : /************************************************************************/
     465             : /*                             AIGLLOpen()                              */
     466             : /*                                                                      */
     467             : /*      Low level fopen() replacement that will try provided, and       */
     468             : /*      upper cased versions of file names.                             */
     469             : /************************************************************************/
     470             : 
     471          33 : VSILFILE *AIGLLOpen(const char *pszFilename, const char *pszAccess)
     472             : 
     473             : {
     474             :     VSILFILE *fp;
     475             : 
     476          33 :     fp = VSIFOpenL(pszFilename, pszAccess);
     477          33 :     if (fp == NULL)
     478             :     {
     479          11 :         char *pszUCFilename = CPLStrdup(pszFilename);
     480             :         int i;
     481             : 
     482          11 :         for (i = (int)strlen(pszUCFilename) - 1;
     483         106 :              pszUCFilename[i] != '/' && pszUCFilename[i] != '\\'; i--)
     484             :         {
     485          95 :             pszUCFilename[i] = (char)toupper((unsigned char)(pszUCFilename[i]));
     486             :         }
     487             : 
     488          11 :         fp = VSIFOpenL(pszUCFilename, pszAccess);
     489             : 
     490          11 :         CPLFree(pszUCFilename);
     491             :     }
     492             : 
     493          33 :     return fp;
     494             : }

Generated by: LCOV version 1.14