LCOV - code coverage report
Current view: top level - frmts/aigrid - gridlib.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 184 430 42.8 %
Date: 2024-11-21 22:18:42 Functions: 8 16 50.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  Arc/Info Binary Grid Translator
       5             :  * Purpose:  Grid file reading code.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Frank Warmerdam
      10             :  * Copyright (c) 2007-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          30 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
      21             : {
      22          30 : }
      23             : #endif
      24             : 
      25             : /************************************************************************/
      26             : /*                    AIGProcessRaw32bitFloatBlock()                    */
      27             : /*                                                                      */
      28             : /*      Process a block using ``00'' (32 bit) raw format.               */
      29             : /************************************************************************/
      30             : 
      31           0 : static CPLErr AIGProcessRaw32BitFloatBlock(GByte *pabyCur, int nDataSize,
      32             :                                            int nMin, int nBlockXSize,
      33             :                                            int nBlockYSize, float *pafData)
      34             : 
      35             : {
      36             :     int i;
      37             : 
      38             :     (void)nMin;
      39           0 :     if (nDataSize < nBlockXSize * nBlockYSize * 4)
      40             :     {
      41           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
      42           0 :         return CE_Failure;
      43             :     }
      44             : 
      45             :     /* -------------------------------------------------------------------- */
      46             :     /*      Collect raw data.                                               */
      47             :     /* -------------------------------------------------------------------- */
      48           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
      49             :     {
      50             :         float fWork;
      51             : 
      52             : #ifdef CPL_LSB
      53           0 :         ((GByte *)&fWork)[3] = *(pabyCur++);
      54           0 :         ((GByte *)&fWork)[2] = *(pabyCur++);
      55           0 :         ((GByte *)&fWork)[1] = *(pabyCur++);
      56           0 :         ((GByte *)&fWork)[0] = *(pabyCur++);
      57             : #else
      58             :         ((GByte *)&fWork)[0] = *(pabyCur++);
      59             :         ((GByte *)&fWork)[1] = *(pabyCur++);
      60             :         ((GByte *)&fWork)[2] = *(pabyCur++);
      61             :         ((GByte *)&fWork)[3] = *(pabyCur++);
      62             : #endif
      63             : 
      64           0 :         pafData[i] = fWork;
      65             :     }
      66             : 
      67           0 :     return (CE_None);
      68             : }
      69             : 
      70             : /************************************************************************/
      71             : /*                      AIGProcessIntConstBlock()                       */
      72             : /*                                                                      */
      73             : /*      Process a block using ``00'' constant 32bit integer format.     */
      74             : /************************************************************************/
      75             : 
      76           0 : static CPLErr AIGProcessIntConstBlock(GByte *pabyCur, int nDataSize, int nMin,
      77             :                                       int nBlockXSize, int nBlockYSize,
      78             :                                       GInt32 *panData)
      79             : 
      80             : {
      81             :     int i;
      82             : 
      83             :     (void)pabyCur;
      84             :     (void)nDataSize;
      85             : 
      86             :     /* -------------------------------------------------------------------- */
      87             :     /*  Apply constant min value.         */
      88             :     /* -------------------------------------------------------------------- */
      89           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
      90           0 :         panData[i] = nMin;
      91             : 
      92           0 :     return (CE_None);
      93             : }
      94             : 
      95             : /************************************************************************/
      96             : /*                         AIGRolloverSignedAdd()                       */
      97             : /************************************************************************/
      98             : 
      99             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
     100           6 : static GInt32 AIGRolloverSignedAdd(GInt32 a, GInt32 b)
     101             : {
     102             :     // Not really portable as assumes complement to 2 representation
     103             :     // but AIG assumes typical unsigned rollover on signed
     104             :     // integer operations.
     105             :     GInt32 res;
     106           6 :     GUInt32 resUnsigned = (GUInt32)(a) + (GUInt32)(b);
     107           6 :     memcpy(&res, &resUnsigned, sizeof(res));
     108           6 :     return res;
     109             : }
     110             : 
     111             : /************************************************************************/
     112             : /*                         AIGProcess32bitRawBlock()                    */
     113             : /*                                                                      */
     114             : /*      Process a block using ``20'' (thirty two bit) raw format.        */
     115             : /************************************************************************/
     116             : 
     117           0 : static CPLErr AIGProcessRaw32BitBlock(GByte *pabyCur, int nDataSize, int nMin,
     118             :                                       int nBlockXSize, int nBlockYSize,
     119             :                                       GInt32 *panData)
     120             : 
     121             : {
     122             :     int i;
     123             : 
     124           0 :     if (nDataSize < nBlockXSize * nBlockYSize * 4)
     125             :     {
     126           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     127           0 :         return CE_Failure;
     128             :     }
     129             : 
     130             :     /* -------------------------------------------------------------------- */
     131             :     /*      Collect raw data.                                               */
     132             :     /* -------------------------------------------------------------------- */
     133           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     134             :     {
     135           0 :         memcpy(panData + i, pabyCur, 4);
     136           0 :         panData[i] = CPL_MSBWORD32(panData[i]);
     137           0 :         panData[i] = AIGRolloverSignedAdd(panData[i], nMin);
     138           0 :         pabyCur += 4;
     139             :     }
     140             : 
     141           0 :     return (CE_None);
     142             : }
     143             : 
     144             : /************************************************************************/
     145             : /*                         AIGProcess16bitRawBlock()                    */
     146             : /*                                                                      */
     147             : /*      Process a block using ``10'' (sixteen bit) raw format.          */
     148             : /************************************************************************/
     149             : 
     150           0 : static CPLErr AIGProcessRaw16BitBlock(GByte *pabyCur, int nDataSize, int nMin,
     151             :                                       int nBlockXSize, int nBlockYSize,
     152             :                                       GInt32 *panData)
     153             : 
     154             : {
     155             :     int i;
     156             : 
     157           0 :     if (nDataSize < nBlockXSize * nBlockYSize * 2)
     158             :     {
     159           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     160           0 :         return CE_Failure;
     161             :     }
     162             : 
     163             :     /* -------------------------------------------------------------------- */
     164             :     /*      Collect raw data.                                               */
     165             :     /* -------------------------------------------------------------------- */
     166           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     167             :     {
     168           0 :         panData[i] = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
     169           0 :         pabyCur += 2;
     170             :     }
     171             : 
     172           0 :     return (CE_None);
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                         AIGProcess4BitRawBlock()                     */
     177             : /*                                                                      */
     178             : /*      Process a block using ``08'' raw format.                        */
     179             : /************************************************************************/
     180             : 
     181           0 : static CPLErr AIGProcessRaw4BitBlock(GByte *pabyCur, int nDataSize, int nMin,
     182             :                                      int nBlockXSize, int nBlockYSize,
     183             :                                      GInt32 *panData)
     184             : 
     185             : {
     186             :     int i;
     187             : 
     188           0 :     if (nDataSize < (nBlockXSize * nBlockYSize + 1) / 2)
     189             :     {
     190           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     191           0 :         return CE_Failure;
     192             :     }
     193             : 
     194             :     /* -------------------------------------------------------------------- */
     195             :     /*      Collect raw data.                                               */
     196             :     /* -------------------------------------------------------------------- */
     197           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     198             :     {
     199           0 :         if (i % 2 == 0)
     200           0 :             panData[i] = AIGRolloverSignedAdd((*(pabyCur)&0xf0) >> 4, nMin);
     201             :         else
     202           0 :             panData[i] = AIGRolloverSignedAdd(*(pabyCur++) & 0xf, nMin);
     203             :     }
     204             : 
     205           0 :     return (CE_None);
     206             : }
     207             : 
     208             : /************************************************************************/
     209             : /*                       AIGProcess1BitRawBlock()                       */
     210             : /*                                                                      */
     211             : /*      Process a block using ``0x01'' raw format.                      */
     212             : /************************************************************************/
     213             : 
     214           0 : static CPLErr AIGProcessRaw1BitBlock(GByte *pabyCur, int nDataSize, int nMin,
     215             :                                      int nBlockXSize, int nBlockYSize,
     216             :                                      GInt32 *panData)
     217             : 
     218             : {
     219             :     int i;
     220             : 
     221           0 :     if (nDataSize < (nBlockXSize * nBlockYSize + 7) / 8)
     222             :     {
     223           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     224           0 :         return CE_Failure;
     225             :     }
     226             : 
     227             :     /* -------------------------------------------------------------------- */
     228             :     /*      Collect raw data.                                               */
     229             :     /* -------------------------------------------------------------------- */
     230           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     231             :     {
     232           0 :         if (pabyCur[i >> 3] & (0x80 >> (i & 0x7)))
     233           0 :             panData[i] = AIGRolloverSignedAdd(1, nMin);
     234             :         else
     235           0 :             panData[i] = 0 + nMin;
     236             :     }
     237             : 
     238           0 :     return (CE_None);
     239             : }
     240             : 
     241             : /************************************************************************/
     242             : /*                         AIGProcessRawBlock()                         */
     243             : /*                                                                      */
     244             : /*      Process a block using ``08'' raw format.                        */
     245             : /************************************************************************/
     246             : 
     247           0 : static CPLErr AIGProcessRawBlock(GByte *pabyCur, int nDataSize, int nMin,
     248             :                                  int nBlockXSize, int nBlockYSize,
     249             :                                  GInt32 *panData)
     250             : 
     251             : {
     252             :     int i;
     253             : 
     254           0 :     if (nDataSize < nBlockXSize * nBlockYSize)
     255             :     {
     256           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     257           0 :         return CE_Failure;
     258             :     }
     259             : 
     260             :     /* -------------------------------------------------------------------- */
     261             :     /*      Collect raw data.                                               */
     262             :     /* -------------------------------------------------------------------- */
     263           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     264             :     {
     265           0 :         panData[i] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
     266             :     }
     267             : 
     268           0 :     return (CE_None);
     269             : }
     270             : 
     271             : /************************************************************************/
     272             : /*                         AIGProcessFFBlock()                          */
     273             : /*                                                                      */
     274             : /*      Process a type 0xFF (CCITT RLE) compressed block.               */
     275             : /************************************************************************/
     276             : 
     277           0 : static CPLErr AIGProcessFFBlock(GByte *pabyCur, int nDataSize, int nMin,
     278             :                                 int nBlockXSize, int nBlockYSize,
     279             :                                 GInt32 *panData)
     280             : 
     281             : {
     282             :     /* -------------------------------------------------------------------- */
     283             :     /*      Convert CCITT compress bitstream into 1bit raw data.            */
     284             :     /* -------------------------------------------------------------------- */
     285             :     CPLErr eErr;
     286           0 :     int i, nDstBytes = (nBlockXSize * nBlockYSize + 7) / 8;
     287             :     unsigned char *pabyIntermediate;
     288             : 
     289           0 :     pabyIntermediate = (unsigned char *)VSI_MALLOC_VERBOSE(nDstBytes);
     290           0 :     if (pabyIntermediate == NULL)
     291             :     {
     292           0 :         return CE_Failure;
     293             :     }
     294             : 
     295           0 :     eErr = DecompressCCITTRLETile(pabyCur, nDataSize, pabyIntermediate,
     296             :                                   nDstBytes, nBlockXSize, nBlockYSize);
     297           0 :     if (eErr != CE_None)
     298             :     {
     299           0 :         CPLFree(pabyIntermediate);
     300           0 :         return eErr;
     301             :     }
     302             : 
     303             :     /* -------------------------------------------------------------------- */
     304             :     /*      Convert the bit buffer into 32bit integers and account for      */
     305             :     /*      nMin.                                                           */
     306             :     /* -------------------------------------------------------------------- */
     307           0 :     for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     308             :     {
     309           0 :         if (pabyIntermediate[i >> 3] & (0x80 >> (i & 0x7)))
     310           0 :             panData[i] = AIGRolloverSignedAdd(nMin, 1);
     311             :         else
     312           0 :             panData[i] = nMin;
     313             :     }
     314             : 
     315           0 :     CPLFree(pabyIntermediate);
     316             : 
     317           0 :     return (CE_None);
     318             : }
     319             : 
     320             : /************************************************************************/
     321             : /*                          AIGProcessBlock()                           */
     322             : /*                                                                      */
     323             : /*      Process a block using ``D7'', ``E0'' or ``DF'' compression.     */
     324             : /************************************************************************/
     325             : 
     326           2 : static CPLErr AIGProcessBlock(GByte *pabyCur, int nDataSize, int nMin,
     327             :                               int nMagic, int nBlockXSize, int nBlockYSize,
     328             :                               GInt32 *panData)
     329             : 
     330             : {
     331             :     int nTotPixels, nPixels;
     332             :     int i;
     333             : 
     334             :     /* ==================================================================== */
     335             :     /*     Process runs till we are done.                                  */
     336             :     /* ==================================================================== */
     337           2 :     nTotPixels = nBlockXSize * nBlockYSize;
     338           2 :     nPixels = 0;
     339             : 
     340          22 :     while (nPixels < nTotPixels && nDataSize > 0)
     341             :     {
     342          20 :         int nMarker = *(pabyCur++);
     343             : 
     344          20 :         nDataSize--;
     345             : 
     346             :         /* --------------------------------------------------------------------
     347             :          */
     348             :         /*      Repeat data - four byte data block (0xE0) */
     349             :         /* --------------------------------------------------------------------
     350             :          */
     351          20 :         if (nMagic == 0xE0)
     352             :         {
     353             :             GInt32 nValue;
     354             : 
     355           0 :             if (nMarker + nPixels > nTotPixels)
     356             :             {
     357           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     358             :                          "Run too long in AIGProcessBlock, needed %d values, "
     359             :                          "got %d.",
     360             :                          nTotPixels - nPixels, nMarker);
     361           0 :                 return CE_Failure;
     362             :             }
     363             : 
     364           0 :             if (nDataSize < 4)
     365             :             {
     366           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     367           0 :                 return CE_Failure;
     368             :             }
     369             : 
     370           0 :             nValue = 0;
     371           0 :             memcpy(&nValue, pabyCur, 4);
     372           0 :             pabyCur += 4;
     373           0 :             nDataSize -= 4;
     374             : 
     375           0 :             nValue = CPL_MSBWORD32(nValue);
     376           0 :             nValue = AIGRolloverSignedAdd(nValue, nMin);
     377           0 :             for (i = 0; i < nMarker; i++)
     378           0 :                 panData[nPixels++] = nValue;
     379             :         }
     380             : 
     381             :         /* --------------------------------------------------------------------
     382             :          */
     383             :         /*      Repeat data - two byte data block (0xF0) */
     384             :         /* --------------------------------------------------------------------
     385             :          */
     386          20 :         else if (nMagic == 0xF0)
     387             :         {
     388             :             GInt32 nValue;
     389             : 
     390           0 :             if (nMarker + nPixels > nTotPixels)
     391             :             {
     392           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     393             :                          "Run too long in AIGProcessBlock, needed %d values, "
     394             :                          "got %d.",
     395             :                          nTotPixels - nPixels, nMarker);
     396           0 :                 return CE_Failure;
     397             :             }
     398             : 
     399           0 :             if (nDataSize < 2)
     400             :             {
     401           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     402           0 :                 return CE_Failure;
     403             :             }
     404             : 
     405           0 :             nValue = AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
     406           0 :             pabyCur += 2;
     407           0 :             nDataSize -= 2;
     408             : 
     409           0 :             for (i = 0; i < nMarker; i++)
     410           0 :                 panData[nPixels++] = nValue;
     411             :         }
     412             : 
     413             :         /* --------------------------------------------------------------------
     414             :          */
     415             :         /*      Repeat data - one byte data block (0xFC) */
     416             :         /* --------------------------------------------------------------------
     417             :          */
     418          20 :         else if (nMagic == 0xFC || nMagic == 0xF8)
     419           0 :         {
     420             :             GInt32 nValue;
     421             : 
     422           0 :             if (nMarker + nPixels > nTotPixels)
     423             :             {
     424           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     425             :                          "Run too long in AIGProcessBlock, needed %d values, "
     426             :                          "got %d.",
     427             :                          nTotPixels - nPixels, nMarker);
     428           0 :                 return CE_Failure;
     429             :             }
     430             : 
     431           0 :             if (nDataSize < 1)
     432             :             {
     433           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Block too small");
     434           0 :                 return CE_Failure;
     435             :             }
     436             : 
     437           0 :             nValue = AIGRolloverSignedAdd(*(pabyCur++), nMin);
     438           0 :             nDataSize--;
     439             : 
     440           0 :             for (i = 0; i < nMarker; i++)
     441           0 :                 panData[nPixels++] = nValue;
     442             :         }
     443             : 
     444             :         /* --------------------------------------------------------------------
     445             :          */
     446             :         /*      Repeat data - no actual data, just assign minimum (0xDF) */
     447             :         /* --------------------------------------------------------------------
     448             :          */
     449          20 :         else if (nMagic == 0xDF && nMarker < 128)
     450             :         {
     451           0 :             if (nMarker + nPixels > nTotPixels)
     452             :             {
     453           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     454             :                          "Run too long in AIGProcessBlock, needed %d values, "
     455             :                          "got %d.",
     456             :                          nTotPixels - nPixels, nMarker);
     457           0 :                 return CE_Failure;
     458             :             }
     459             : 
     460           0 :             for (i = 0; i < nMarker; i++)
     461           0 :                 panData[nPixels++] = nMin;
     462             :         }
     463             : 
     464             :         /* --------------------------------------------------------------------
     465             :          */
     466             :         /*      Literal data (0xD7): 8bit values. */
     467             :         /* --------------------------------------------------------------------
     468             :          */
     469          20 :         else if (nMagic == 0xD7 && nMarker < 128)
     470             :         {
     471           2 :             if (nMarker + nPixels > nTotPixels)
     472             :             {
     473           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     474             :                          "Run too long in AIGProcessBlock, needed %d values, "
     475             :                          "got %d.",
     476             :                          nTotPixels - nPixels, nMarker);
     477           0 :                 return CE_Failure;
     478             :             }
     479             : 
     480           8 :             while (nMarker > 0 && nDataSize > 0)
     481             :             {
     482           6 :                 panData[nPixels++] = AIGRolloverSignedAdd(*(pabyCur++), nMin);
     483           6 :                 nMarker--;
     484           6 :                 nDataSize--;
     485             :             }
     486             :         }
     487             : 
     488             :         /* --------------------------------------------------------------------
     489             :          */
     490             :         /*      Literal data (0xCF): 16 bit values. */
     491             :         /* --------------------------------------------------------------------
     492             :          */
     493          18 :         else if (nMagic == 0xCF && nMarker < 128)
     494           0 :         {
     495             :             GInt32 nValue;
     496             : 
     497           0 :             if (nMarker + nPixels > nTotPixels)
     498             :             {
     499           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     500             :                          "Run too long in AIGProcessBlock, needed %d values, "
     501             :                          "got %d.",
     502             :                          nTotPixels - nPixels, nMarker);
     503           0 :                 return CE_Failure;
     504             :             }
     505             : 
     506           0 :             while (nMarker > 0 && nDataSize >= 2)
     507             :             {
     508             :                 nValue =
     509           0 :                     AIGRolloverSignedAdd(pabyCur[0] * 256 + pabyCur[1], nMin);
     510           0 :                 panData[nPixels++] = nValue;
     511           0 :                 pabyCur += 2;
     512             : 
     513           0 :                 nMarker--;
     514           0 :                 nDataSize -= 2;
     515             :             }
     516             :         }
     517             : 
     518             :         /* --------------------------------------------------------------------
     519             :          */
     520             :         /*      Nodata repeat */
     521             :         /* --------------------------------------------------------------------
     522             :          */
     523          18 :         else if (nMarker > 128)
     524             :         {
     525          18 :             nMarker = 256 - nMarker;
     526             : 
     527          18 :             if (nMarker + nPixels > nTotPixels)
     528             :             {
     529           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     530             :                          "Run too long in AIGProcessBlock, needed %d values, "
     531             :                          "got %d.",
     532             :                          nTotPixels - nPixels, nMarker);
     533           0 :                 return CE_Failure;
     534             :             }
     535             : 
     536        2060 :             while (nMarker > 0)
     537             :             {
     538        2042 :                 panData[nPixels++] = ESRI_GRID_NO_DATA;
     539        2042 :                 nMarker--;
     540             :             }
     541             :         }
     542             : 
     543             :         else
     544             :         {
     545           0 :             return CE_Failure;
     546             :         }
     547             :     }
     548             : 
     549           2 :     if (nPixels < nTotPixels || nDataSize < 0)
     550             :     {
     551           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     552             :                  "Ran out of data processing block with nMagic=%d.", nMagic);
     553           0 :         return CE_Failure;
     554             :     }
     555             : 
     556           2 :     return CE_None;
     557             : }
     558             : 
     559             : /************************************************************************/
     560             : /*                            AIGReadBlock()                            */
     561             : /*                                                                      */
     562             : /*      Read a single block of integer grid data.                       */
     563             : /************************************************************************/
     564             : 
     565           2 : CPLErr AIGReadBlock(VSILFILE *fp, GUInt32 nBlockOffset, int nBlockSize,
     566             :                     int nBlockXSize, int nBlockYSize, GInt32 *panData,
     567             :                     int nCellType, int bCompressed)
     568             : 
     569             : {
     570             :     GByte *pabyRaw, *pabyCur;
     571             :     CPLErr eErr;
     572           2 :     int i, nMagic, nMinSize = 0, nDataSize;
     573           2 :     GInt32 nMin = 0;
     574             : 
     575             :     /* -------------------------------------------------------------------- */
     576             :     /*      If the block has zero size it is all dummies.                   */
     577             :     /* -------------------------------------------------------------------- */
     578           2 :     if (nBlockSize == 0)
     579             :     {
     580           0 :         for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     581           0 :             panData[i] = ESRI_GRID_NO_DATA;
     582             : 
     583           0 :         return (CE_None);
     584             :     }
     585             : 
     586             :     /* -------------------------------------------------------------------- */
     587             :     /*      Read the block into memory.                                     */
     588             :     /* -------------------------------------------------------------------- */
     589           2 :     if (nBlockSize <= 0 || nBlockSize > 65535 * 2)
     590             :     {
     591           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid block size : %d",
     592             :                  nBlockSize);
     593           0 :         return CE_Failure;
     594             :     }
     595             : 
     596           2 :     pabyRaw = (GByte *)VSIMalloc(nBlockSize + 2);
     597           2 :     if (pabyRaw == NULL)
     598             :     {
     599           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     600             :                  "Cannot allocate memory for block");
     601           0 :         return CE_Failure;
     602             :     }
     603             : 
     604           4 :     if (VSIFSeekL(fp, nBlockOffset, SEEK_SET) != 0 ||
     605           2 :         VSIFReadL(pabyRaw, nBlockSize + 2, 1, fp) != 1)
     606             :     {
     607           0 :         memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
     608           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     609             :                  "Read of %d bytes from offset %d for grid block failed.",
     610             :                  nBlockSize + 2, nBlockOffset);
     611           0 :         CPLFree(pabyRaw);
     612           0 :         return CE_Failure;
     613             :     }
     614             : 
     615             :     /* -------------------------------------------------------------------- */
     616             :     /*      Verify the block size.                                          */
     617             :     /* -------------------------------------------------------------------- */
     618           2 :     if (nBlockSize != (pabyRaw[0] * 256 + pabyRaw[1]) * 2)
     619             :     {
     620           0 :         memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
     621           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     622             :                  "Block is corrupt, block size was %d, but expected to be %d.",
     623           0 :                  (pabyRaw[0] * 256 + pabyRaw[1]) * 2, nBlockSize);
     624           0 :         CPLFree(pabyRaw);
     625           0 :         return CE_Failure;
     626             :     }
     627             : 
     628           2 :     nDataSize = nBlockSize;
     629             : 
     630             :     /* -------------------------------------------------------------------- */
     631             :     /*      Handle float files and uncompressed integer files directly.     */
     632             :     /* -------------------------------------------------------------------- */
     633           2 :     if (nCellType == AIG_CELLTYPE_FLOAT)
     634             :     {
     635           0 :         AIGProcessRaw32BitFloatBlock(pabyRaw + 2, nDataSize, 0, nBlockXSize,
     636             :                                      nBlockYSize, (float *)panData);
     637           0 :         CPLFree(pabyRaw);
     638             : 
     639           0 :         return CE_None;
     640             :     }
     641             : 
     642           2 :     if (nCellType == AIG_CELLTYPE_INT && !bCompressed)
     643             :     {
     644           0 :         AIGProcessRaw32BitBlock(pabyRaw + 2, nDataSize, nMin, nBlockXSize,
     645             :                                 nBlockYSize, panData);
     646           0 :         CPLFree(pabyRaw);
     647           0 :         return CE_None;
     648             :     }
     649             : 
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      Collect minimum value.                                          */
     652             :     /* -------------------------------------------------------------------- */
     653             : 
     654             :     /* The first 2 bytes that give the block size are not included in nDataSize
     655             :      */
     656             :     /* and have already been safely read */
     657           2 :     pabyCur = pabyRaw + 2;
     658             : 
     659             :     /* Need at least 2 byte to read the nMinSize and the nMagic */
     660           2 :     if (nDataSize < 2)
     661             :     {
     662           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     663             :                  "Corrupt block. Need 2 bytes to read nMagic and nMinSize, "
     664             :                  "only %d available",
     665             :                  nDataSize);
     666           0 :         CPLFree(pabyRaw);
     667           0 :         return CE_Failure;
     668             :     }
     669           2 :     nMagic = pabyCur[0];
     670           2 :     nMinSize = pabyCur[1];
     671           2 :     pabyCur += 2;
     672           2 :     nDataSize -= 2;
     673             : 
     674             :     /* Need at least nMinSize bytes to read the nMin value */
     675           2 :     if (nDataSize < nMinSize)
     676             :     {
     677           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     678             :                  "Corrupt block. Need %d bytes to read nMin. Only %d available",
     679             :                  nMinSize, nDataSize);
     680           0 :         CPLFree(pabyRaw);
     681           0 :         return CE_Failure;
     682             :     }
     683             : 
     684           2 :     if (nMinSize > 4)
     685             :     {
     686           0 :         memset(panData, 0, sizeof(int32_t) * nBlockXSize * nBlockYSize);
     687           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     688             :                  "Corrupt 'minsize' of %d in block header.  Read aborted.",
     689             :                  nMinSize);
     690           0 :         CPLFree(pabyRaw);
     691           0 :         return CE_Failure;
     692             :     }
     693             : 
     694           2 :     if (nMinSize == 4)
     695             :     {
     696           0 :         memcpy(&nMin, pabyCur, 4);
     697           0 :         nMin = CPL_MSBWORD32(nMin);
     698           0 :         pabyCur += 4;
     699             :     }
     700             :     else
     701             :     {
     702           2 :         nMin = 0;
     703           2 :         for (i = 0; i < nMinSize; i++)
     704             :         {
     705           0 :             nMin = nMin * 256 + *pabyCur;
     706           0 :             pabyCur++;
     707             :         }
     708             : 
     709             :         /* If nMinSize = 0, then we might have only 4 bytes in pabyRaw */
     710             :         /* don't try to read the 5th one then */
     711           2 :         if (nMinSize != 0 && pabyRaw[4] > 127)
     712             :         {
     713           0 :             if (nMinSize == 2)
     714           0 :                 nMin = nMin - 65536;
     715           0 :             else if (nMinSize == 1)
     716           0 :                 nMin = nMin - 256;
     717           0 :             else if (nMinSize == 3)
     718           0 :                 nMin = nMin - 256 * 256 * 256;
     719             :         }
     720             :     }
     721             : 
     722           2 :     nDataSize -= nMinSize;
     723             : 
     724             :     /* -------------------------------------------------------------------- */
     725             :     /*  Call an appropriate handler depending on magic code.    */
     726             :     /* -------------------------------------------------------------------- */
     727           2 :     eErr = CE_None;
     728           2 :     if (nMagic == 0x08)
     729             :     {
     730           0 :         AIGProcessRawBlock(pabyCur, nDataSize, nMin, nBlockXSize, nBlockYSize,
     731             :                            panData);
     732             :     }
     733           2 :     else if (nMagic == 0x04)
     734             :     {
     735           0 :         AIGProcessRaw4BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
     736             :                                nBlockYSize, panData);
     737             :     }
     738           2 :     else if (nMagic == 0x01)
     739             :     {
     740           0 :         AIGProcessRaw1BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
     741             :                                nBlockYSize, panData);
     742             :     }
     743           2 :     else if (nMagic == 0x00)
     744             :     {
     745           0 :         AIGProcessIntConstBlock(pabyCur, nDataSize, nMin, nBlockXSize,
     746             :                                 nBlockYSize, panData);
     747             :     }
     748           2 :     else if (nMagic == 0x10)
     749             :     {
     750           0 :         AIGProcessRaw16BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
     751             :                                 nBlockYSize, panData);
     752             :     }
     753           2 :     else if (nMagic == 0x20)
     754             :     {
     755           0 :         AIGProcessRaw32BitBlock(pabyCur, nDataSize, nMin, nBlockXSize,
     756             :                                 nBlockYSize, panData);
     757             :     }
     758           2 :     else if (nMagic == 0xFF)
     759             :     {
     760           0 :         eErr = AIGProcessFFBlock(pabyCur, nDataSize, nMin, nBlockXSize,
     761             :                                  nBlockYSize, panData);
     762             :     }
     763             :     else
     764             :     {
     765           2 :         eErr = AIGProcessBlock(pabyCur, nDataSize, nMin, nMagic, nBlockXSize,
     766             :                                nBlockYSize, panData);
     767             : 
     768           2 :         if (eErr == CE_Failure)
     769             :         {
     770             :             static int bHasWarned = FALSE;
     771             : 
     772           0 :             for (i = 0; i < nBlockXSize * nBlockYSize; i++)
     773           0 :                 panData[i] = ESRI_GRID_NO_DATA;
     774             : 
     775           0 :             if (!bHasWarned)
     776             :             {
     777           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
     778             :                          "Unsupported Arc/Info Binary Grid tile of type 0x%X"
     779             :                          " encountered.\n"
     780             :                          "This and subsequent unsupported tile types set to"
     781             :                          " no data value.\n",
     782             :                          nMagic);
     783           0 :                 bHasWarned = TRUE;
     784             :             }
     785             :         }
     786             :     }
     787             : 
     788           2 :     CPLFree(pabyRaw);
     789             : 
     790           2 :     return eErr;
     791             : }
     792             : 
     793             : /************************************************************************/
     794             : /*                           AIGReadHeader()                            */
     795             : /*                                                                      */
     796             : /*      Read the hdr.adf file, and populate the given info structure    */
     797             : /*      appropriately.                                                  */
     798             : /************************************************************************/
     799             : 
     800           9 : CPLErr AIGReadHeader(const char *pszCoverName, AIGInfo_t *psInfo)
     801             : 
     802             : {
     803             :     char *pszHDRFilename;
     804             :     VSILFILE *fp;
     805             :     GByte abyData[308];
     806           9 :     const size_t nHDRFilenameLen = strlen(pszCoverName) + 30;
     807             : 
     808             :     /* -------------------------------------------------------------------- */
     809             :     /*      Open the file hdr.adf file.                                     */
     810             :     /* -------------------------------------------------------------------- */
     811           9 :     pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
     812           9 :     snprintf(pszHDRFilename, nHDRFilenameLen, "%s/hdr.adf", pszCoverName);
     813             : 
     814           9 :     fp = AIGLLOpen(pszHDRFilename, "rb");
     815             : 
     816           9 :     if (fp == NULL)
     817             :     {
     818           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     819             :                  "Failed to open grid header file:\n%s\n", pszHDRFilename);
     820             : 
     821           0 :         CPLFree(pszHDRFilename);
     822           0 :         return (CE_Failure);
     823             :     }
     824             : 
     825           9 :     CPLFree(pszHDRFilename);
     826             : 
     827             :     /* -------------------------------------------------------------------- */
     828             :     /*      Read the whole file (we expect it to always be 308 bytes        */
     829             :     /*      long.                                                           */
     830             :     /* -------------------------------------------------------------------- */
     831             : 
     832           9 :     if (VSIFReadL(abyData, 1, 308, fp) != 308)
     833             :     {
     834           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     835           0 :         return (CE_Failure);
     836             :     }
     837             : 
     838           9 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     839             : 
     840             :     /* -------------------------------------------------------------------- */
     841             :     /*      Read the block size information.                                */
     842             :     /* -------------------------------------------------------------------- */
     843           9 :     memcpy(&(psInfo->nCellType), abyData + 16, 4);
     844           9 :     memcpy(&(psInfo->bCompressed), abyData + 20, 4);
     845           9 :     memcpy(&(psInfo->nBlocksPerRow), abyData + 288, 4);
     846           9 :     memcpy(&(psInfo->nBlocksPerColumn), abyData + 292, 4);
     847           9 :     memcpy(&(psInfo->nBlockXSize), abyData + 296, 4);
     848           9 :     memcpy(&(psInfo->nBlockYSize), abyData + 304, 4);
     849           9 :     memcpy(&(psInfo->dfCellSizeX), abyData + 256, 8);
     850           9 :     memcpy(&(psInfo->dfCellSizeY), abyData + 264, 8);
     851             : 
     852             : #ifdef CPL_LSB
     853           9 :     psInfo->nCellType = CPL_SWAP32(psInfo->nCellType);
     854           9 :     psInfo->bCompressed = CPL_SWAP32(psInfo->bCompressed);
     855           9 :     psInfo->nBlocksPerRow = CPL_SWAP32(psInfo->nBlocksPerRow);
     856           9 :     psInfo->nBlocksPerColumn = CPL_SWAP32(psInfo->nBlocksPerColumn);
     857           9 :     psInfo->nBlockXSize = CPL_SWAP32(psInfo->nBlockXSize);
     858           9 :     psInfo->nBlockYSize = CPL_SWAP32(psInfo->nBlockYSize);
     859           9 :     CPL_SWAPDOUBLE(&(psInfo->dfCellSizeX));
     860           9 :     CPL_SWAPDOUBLE(&(psInfo->dfCellSizeY));
     861             : #endif
     862             : 
     863           9 :     psInfo->bCompressed = !psInfo->bCompressed;
     864             : 
     865           9 :     return (CE_None);
     866             : }
     867             : 
     868             : /************************************************************************/
     869             : /*                         AIGReadBlockIndex()                          */
     870             : /*                                                                      */
     871             : /*      Read the w001001x.adf file, and populate the given info         */
     872             : /*      structure with the block offsets, and sizes.                    */
     873             : /************************************************************************/
     874             : 
     875           3 : CPLErr AIGReadBlockIndex(AIGInfo_t *psInfo, AIGTileInfo *psTInfo,
     876             :                          const char *pszBasename)
     877             : 
     878             : {
     879             :     char *pszHDRFilename;
     880             :     VSILFILE *fp;
     881             :     int i;
     882             :     GUInt32 nValue, nLength;
     883             :     GUInt32 *panIndex;
     884             :     GByte abyHeader[8];
     885           3 :     const size_t nHDRFilenameLen = strlen(psInfo->pszCoverName) + 40;
     886             : 
     887             :     /* -------------------------------------------------------------------- */
     888             :     /*      Open the file hdr.adf file.                                     */
     889             :     /* -------------------------------------------------------------------- */
     890           3 :     pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
     891           3 :     snprintf(pszHDRFilename, nHDRFilenameLen, "%s/%sx.adf",
     892             :              psInfo->pszCoverName, pszBasename);
     893             : 
     894           3 :     fp = AIGLLOpen(pszHDRFilename, "rb");
     895             : 
     896           3 :     if (fp == NULL)
     897             :     {
     898           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     899             :                  "Failed to open grid block index file:\n%s\n", pszHDRFilename);
     900             : 
     901           0 :         CPLFree(pszHDRFilename);
     902           0 :         return (CE_Failure);
     903             :     }
     904             : 
     905           3 :     CPLFree(pszHDRFilename);
     906             : 
     907             :     /* -------------------------------------------------------------------- */
     908             :     /*      Verify the magic number.  This is often corrupted by CR/LF      */
     909             :     /*      translation.                                                    */
     910             :     /* -------------------------------------------------------------------- */
     911           3 :     if (VSIFReadL(abyHeader, 1, 8, fp) != 8)
     912             :     {
     913           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     914           0 :         return CE_Failure;
     915             :     }
     916           3 :     if (abyHeader[3] == 0x0D && abyHeader[4] == 0x0A)
     917             :     {
     918           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     919             :                  "w001001x.adf file header has been corrupted by unix to dos "
     920             :                  "text conversion.");
     921           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     922           0 :         return CE_Failure;
     923             :     }
     924             : 
     925           3 :     if (abyHeader[0] != 0x00 || abyHeader[1] != 0x00 || abyHeader[2] != 0x27 ||
     926           3 :         abyHeader[3] != 0x0A || abyHeader[4] != 0xFF || abyHeader[5] != 0xFF)
     927             :     {
     928           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     929             :                  "w001001x.adf file header magic number is corrupt.");
     930           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     931           0 :         return CE_Failure;
     932             :     }
     933             : 
     934             :     /* -------------------------------------------------------------------- */
     935             :     /*      Get the file length (in 2 byte shorts)                          */
     936             :     /* -------------------------------------------------------------------- */
     937           3 :     if (VSIFSeekL(fp, 24, SEEK_SET) != 0 || VSIFReadL(&nValue, 1, 4, fp) != 4)
     938             :     {
     939           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     940           0 :         return CE_Failure;
     941             :     }
     942             : 
     943           3 :     nValue = CPL_MSBWORD32(nValue);
     944           3 :     if (nValue > INT_MAX)
     945             :     {
     946           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
     947           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     948           0 :         return CE_Failure;
     949             :     }
     950           3 :     nLength = nValue * 2;
     951           3 :     if (nLength <= 100)
     952             :     {
     953           0 :         CPLError(CE_Failure, CPLE_AppDefined, "AIGReadBlockIndex: Bad length");
     954           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     955           0 :         return CE_Failure;
     956             :     }
     957             : 
     958             :     /* -------------------------------------------------------------------- */
     959             :     /*      Allocate buffer, and read the file (from beyond the header)     */
     960             :     /*      into the buffer.                                                */
     961             :     /* -------------------------------------------------------------------- */
     962           3 :     psTInfo->nBlocks = (nLength - 100) / 8;
     963           3 :     if (psTInfo->nBlocks >= 1000000)
     964             :     {
     965             :         // Avoid excessive memory consumption.
     966             :         vsi_l_offset nFileSize;
     967           0 :         VSIFSeekL(fp, 0, SEEK_END);
     968           0 :         nFileSize = VSIFTellL(fp);
     969           0 :         if (nFileSize < 100 ||
     970           0 :             (vsi_l_offset)psTInfo->nBlocks > (nFileSize - 100) / 8)
     971             :         {
     972           0 :             CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     973           0 :             return CE_Failure;
     974             :         }
     975             :     }
     976           3 :     panIndex = (GUInt32 *)VSI_MALLOC2_VERBOSE(psTInfo->nBlocks, 8);
     977           3 :     if (panIndex == NULL)
     978             :     {
     979           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     980           0 :         return CE_Failure;
     981             :     }
     982           3 :     if (VSIFSeekL(fp, 100, SEEK_SET) != 0 ||
     983           3 :         (int)VSIFReadL(panIndex, 8, psTInfo->nBlocks, fp) != psTInfo->nBlocks)
     984             :     {
     985           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     986             :                  "AIGReadBlockIndex: Cannot read block info");
     987           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     988           0 :         CPLFree(panIndex);
     989           0 :         return CE_Failure;
     990             :     }
     991             : 
     992           3 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
     993             : 
     994             :     /* -------------------------------------------------------------------- */
     995             :     /*  Allocate AIGInfo block info arrays.       */
     996             :     /* -------------------------------------------------------------------- */
     997           3 :     psTInfo->panBlockOffset =
     998           3 :         (GUInt32 *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
     999           3 :     psTInfo->panBlockSize = (int *)VSI_MALLOC2_VERBOSE(4, psTInfo->nBlocks);
    1000           3 :     if (psTInfo->panBlockOffset == NULL || psTInfo->panBlockSize == NULL)
    1001             :     {
    1002           0 :         CPLFree(psTInfo->panBlockOffset);
    1003           0 :         CPLFree(psTInfo->panBlockSize);
    1004           0 :         psTInfo->panBlockOffset = NULL;
    1005           0 :         psTInfo->panBlockSize = NULL;
    1006           0 :         CPLFree(panIndex);
    1007           0 :         return CE_Failure;
    1008             :     }
    1009             : 
    1010             :     /* -------------------------------------------------------------------- */
    1011             :     /*      Populate the block information.                                 */
    1012             :     /* -------------------------------------------------------------------- */
    1013           5 :     for (i = 0; i < psTInfo->nBlocks; i++)
    1014             :     {
    1015             :         GUInt32 nVal;
    1016             : 
    1017           3 :         nVal = CPL_MSBWORD32(panIndex[i * 2]);
    1018           3 :         if (nVal >= INT_MAX)
    1019             :         {
    1020           1 :             CPLError(CE_Failure, CPLE_AppDefined,
    1021             :                      "AIGReadBlockIndex: Bad offset for block %d", i);
    1022           1 :             CPLFree(psTInfo->panBlockOffset);
    1023           1 :             CPLFree(psTInfo->panBlockSize);
    1024           1 :             psTInfo->panBlockOffset = NULL;
    1025           1 :             psTInfo->panBlockSize = NULL;
    1026           1 :             CPLFree(panIndex);
    1027           1 :             return CE_Failure;
    1028             :         }
    1029           2 :         psTInfo->panBlockOffset[i] = nVal * 2;
    1030             : 
    1031           2 :         nVal = CPL_MSBWORD32(panIndex[i * 2 + 1]);
    1032           2 :         if (nVal >= INT_MAX / 2)
    1033             :         {
    1034           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1035             :                      "AIGReadBlockIndex: Bad size for block %d", i);
    1036           0 :             CPLFree(psTInfo->panBlockOffset);
    1037           0 :             CPLFree(psTInfo->panBlockSize);
    1038           0 :             psTInfo->panBlockOffset = NULL;
    1039           0 :             psTInfo->panBlockSize = NULL;
    1040           0 :             CPLFree(panIndex);
    1041           0 :             return CE_Failure;
    1042             :         }
    1043           2 :         psTInfo->panBlockSize[i] = nVal * 2;
    1044             :     }
    1045             : 
    1046           2 :     CPLFree(panIndex);
    1047             : 
    1048           2 :     return (CE_None);
    1049             : }
    1050             : 
    1051             : /************************************************************************/
    1052             : /*                           AIGReadBounds()                            */
    1053             : /*                                                                      */
    1054             : /*      Read the dblbnd.adf file for the georeferenced bounds.          */
    1055             : /************************************************************************/
    1056             : 
    1057           9 : CPLErr AIGReadBounds(const char *pszCoverName, AIGInfo_t *psInfo)
    1058             : 
    1059             : {
    1060             :     char *pszHDRFilename;
    1061             :     VSILFILE *fp;
    1062             :     double adfBound[4];
    1063           9 :     const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
    1064             : 
    1065             :     /* -------------------------------------------------------------------- */
    1066             :     /*      Open the file dblbnd.adf file.                                  */
    1067             :     /* -------------------------------------------------------------------- */
    1068           9 :     pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
    1069           9 :     snprintf(pszHDRFilename, nHDRFilenameLen, "%s/dblbnd.adf", pszCoverName);
    1070             : 
    1071           9 :     fp = AIGLLOpen(pszHDRFilename, "rb");
    1072             : 
    1073           9 :     if (fp == NULL)
    1074             :     {
    1075           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1076             :                  "Failed to open grid bounds file:\n%s\n", pszHDRFilename);
    1077             : 
    1078           0 :         CPLFree(pszHDRFilename);
    1079           0 :         return (CE_Failure);
    1080             :     }
    1081             : 
    1082           9 :     CPLFree(pszHDRFilename);
    1083             : 
    1084             :     /* -------------------------------------------------------------------- */
    1085             :     /*      Get the contents - four doubles.                                */
    1086             :     /* -------------------------------------------------------------------- */
    1087           9 :     if (VSIFReadL(adfBound, 1, 32, fp) != 32)
    1088             :     {
    1089           0 :         CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
    1090           0 :         return CE_Failure;
    1091             :     }
    1092             : 
    1093           9 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
    1094             : 
    1095             : #ifdef CPL_LSB
    1096           9 :     CPL_SWAPDOUBLE(adfBound + 0);
    1097           9 :     CPL_SWAPDOUBLE(adfBound + 1);
    1098           9 :     CPL_SWAPDOUBLE(adfBound + 2);
    1099           9 :     CPL_SWAPDOUBLE(adfBound + 3);
    1100             : #endif
    1101             : 
    1102           9 :     psInfo->dfLLX = adfBound[0];
    1103           9 :     psInfo->dfLLY = adfBound[1];
    1104           9 :     psInfo->dfURX = adfBound[2];
    1105           9 :     psInfo->dfURY = adfBound[3];
    1106             : 
    1107           9 :     return (CE_None);
    1108             : }
    1109             : 
    1110             : /************************************************************************/
    1111             : /*                         AIGReadStatistics()                          */
    1112             : /*                                                                      */
    1113             : /*      Read the sta.adf file for the layer statistics.                 */
    1114             : /************************************************************************/
    1115             : 
    1116           9 : CPLErr AIGReadStatistics(const char *pszCoverName, AIGInfo_t *psInfo)
    1117             : 
    1118             : {
    1119             :     char *pszHDRFilename;
    1120             :     VSILFILE *fp;
    1121             :     double adfStats[4];
    1122           9 :     const size_t nHDRFilenameLen = strlen(pszCoverName) + 40;
    1123             :     size_t nRead;
    1124             : 
    1125           9 :     psInfo->dfMin = 0.0;
    1126           9 :     psInfo->dfMax = 0.0;
    1127           9 :     psInfo->dfMean = 0.0;
    1128           9 :     psInfo->dfStdDev = -1.0;
    1129             : 
    1130             :     /* -------------------------------------------------------------------- */
    1131             :     /*      Open the file sta.adf file.                                     */
    1132             :     /* -------------------------------------------------------------------- */
    1133           9 :     pszHDRFilename = (char *)CPLMalloc(nHDRFilenameLen);
    1134           9 :     snprintf(pszHDRFilename, nHDRFilenameLen, "%s/sta.adf", pszCoverName);
    1135             : 
    1136           9 :     fp = AIGLLOpen(pszHDRFilename, "rb");
    1137             : 
    1138           9 :     if (fp == NULL)
    1139             :     {
    1140           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1141             :                  "Failed to open grid statistics file:\n%s\n", pszHDRFilename);
    1142             : 
    1143           0 :         CPLFree(pszHDRFilename);
    1144           0 :         return (CE_Failure);
    1145             :     }
    1146             : 
    1147             :     /* -------------------------------------------------------------------- */
    1148             :     /*      Get the contents - 3 or 4 doubles.                              */
    1149             :     /* -------------------------------------------------------------------- */
    1150           9 :     nRead = VSIFReadL(adfStats, 1, 32, fp);
    1151             : 
    1152           9 :     CPL_IGNORE_RET_VAL_INT(VSIFCloseL(fp));
    1153             : 
    1154           9 :     if (nRead == 32)
    1155             :     {
    1156             : #ifdef CPL_LSB
    1157           8 :         CPL_SWAPDOUBLE(adfStats + 0);
    1158           8 :         CPL_SWAPDOUBLE(adfStats + 1);
    1159           8 :         CPL_SWAPDOUBLE(adfStats + 2);
    1160           8 :         CPL_SWAPDOUBLE(adfStats + 3);
    1161             : #endif
    1162             : 
    1163           8 :         psInfo->dfMin = adfStats[0];
    1164           8 :         psInfo->dfMax = adfStats[1];
    1165           8 :         psInfo->dfMean = adfStats[2];
    1166           8 :         psInfo->dfStdDev = adfStats[3];
    1167             :     }
    1168           1 :     else if (nRead == 24)
    1169             :     {
    1170             :         /* See dataset at https://trac.osgeo.org/gdal/ticket/6633 */
    1171             :         /* In that case, we have only min, max and mean, in LSB ordering */
    1172             :         CPL_LSBPTR64(adfStats + 0);
    1173             :         CPL_LSBPTR64(adfStats + 1);
    1174             :         CPL_LSBPTR64(adfStats + 2);
    1175             : 
    1176           1 :         psInfo->dfMin = adfStats[0];
    1177           1 :         psInfo->dfMax = adfStats[1];
    1178           1 :         psInfo->dfMean = adfStats[2];
    1179             :     }
    1180             :     else
    1181             :     {
    1182           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Wrong content for %s",
    1183             :                  pszHDRFilename);
    1184           0 :         CPLFree(pszHDRFilename);
    1185           0 :         return CE_Failure;
    1186             :     }
    1187             : 
    1188           9 :     CPLFree(pszHDRFilename);
    1189           9 :     return CE_None;
    1190             : }

Generated by: LCOV version 1.14