"Fossies" - the Fresh Open Source Software Archive

Member "gdal-3.0.2/frmts/aigrid/aigopen.c" (28 Oct 2019, 19764 Bytes) of package /linux/privat/gdal-3.0.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "aigopen.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.4.1_vs_3.0.0.

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