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

Generated by: LCOV version 1.14