LCOV - code coverage report
Current view: top level - frmts/aigrid - gridlib.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 184 428 43.0 %
Date: 2025-01-18 12:42:00 Functions: 8 16 50.0 %

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

Generated by: LCOV version 1.14