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

Generated by: LCOV version 1.14