LCOV - code coverage report
Current view: top level - frmts/aigrid - aigdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 191 398 48.0 %
Date: 2024-05-03 15:49:35 Functions: 16 22 72.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Arc/Info Binary Grid Driver
       4             :  * Purpose:  Implements GDAL interface to underlying library.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "aigrid.h"
      31             : #include "avc.h"
      32             : #include "cpl_string.h"
      33             : #include "gdal_frmts.h"
      34             : #include "gdal_pam.h"
      35             : #include "gdal_rat.h"
      36             : #include "ogr_spatialref.h"
      37             : 
      38             : #include <vector>
      39             : 
      40             : static CPLString OSR_GDS(char **papszNV, const char *pszField,
      41             :                          const char *pszDefaultValue);
      42             : 
      43             : /************************************************************************/
      44             : /* ==================================================================== */
      45             : /*                              AIGDataset                              */
      46             : /* ==================================================================== */
      47             : /************************************************************************/
      48             : 
      49             : class AIGRasterBand;
      50             : 
      51             : class AIGDataset final : public GDALPamDataset
      52             : {
      53             :     friend class AIGRasterBand;
      54             : 
      55             :     AIGInfo_t *psInfo;
      56             : 
      57             :     char **papszPrj;
      58             :     OGRSpatialReference m_oSRS{};
      59             : 
      60             :     GDALColorTable *poCT;
      61             :     bool bHasReadRat;
      62             : 
      63             :     void TranslateColorTable(const char *);
      64             : 
      65             :     void ReadRAT();
      66             :     GDALRasterAttributeTable *poRAT;
      67             : 
      68             :   public:
      69             :     AIGDataset();
      70             :     ~AIGDataset() override;
      71             : 
      72             :     static GDALDataset *Open(GDALOpenInfo *);
      73             : 
      74             :     CPLErr GetGeoTransform(double *) override;
      75             :     const OGRSpatialReference *GetSpatialRef() const override;
      76             :     char **GetFileList(void) override;
      77             : };
      78             : 
      79             : /************************************************************************/
      80             : /* ==================================================================== */
      81             : /*                            AIGRasterBand                             */
      82             : /* ==================================================================== */
      83             : /************************************************************************/
      84             : 
      85             : class AIGRasterBand final : public GDALPamRasterBand
      86             : 
      87             : {
      88             :     friend class AIGDataset;
      89             : 
      90             :   public:
      91             :     AIGRasterBand(AIGDataset *, int);
      92             : 
      93             :     CPLErr IReadBlock(int, int, void *) override;
      94             :     double GetMinimum(int *pbSuccess) override;
      95             :     double GetMaximum(int *pbSuccess) override;
      96             :     double GetNoDataValue(int *pbSuccess) override;
      97             : 
      98             :     GDALColorInterp GetColorInterpretation() override;
      99             :     GDALColorTable *GetColorTable() override;
     100             :     GDALRasterAttributeTable *GetDefaultRAT() override;
     101             : };
     102             : 
     103             : /************************************************************************/
     104             : /*                           AIGRasterBand()                            */
     105             : /************************************************************************/
     106             : 
     107           9 : AIGRasterBand::AIGRasterBand(AIGDataset *poDSIn, int nBandIn)
     108             : 
     109             : {
     110           9 :     poDS = poDSIn;
     111           9 :     nBand = nBandIn;
     112             : 
     113           9 :     nBlockXSize = poDSIn->psInfo->nBlockXSize;
     114           9 :     nBlockYSize = poDSIn->psInfo->nBlockYSize;
     115             : 
     116           9 :     if (poDSIn->psInfo->nCellType == AIG_CELLTYPE_INT &&
     117           9 :         poDSIn->psInfo->dfMin >= 0.0 && poDSIn->psInfo->dfMax <= 254.0)
     118             :     {
     119           9 :         eDataType = GDT_Byte;
     120             :     }
     121           0 :     else if (poDSIn->psInfo->nCellType == AIG_CELLTYPE_INT &&
     122           0 :              poDSIn->psInfo->dfMin >= -32767 && poDSIn->psInfo->dfMax <= 32767)
     123             :     {
     124           0 :         eDataType = GDT_Int16;
     125             :     }
     126           0 :     else if (poDSIn->psInfo->nCellType == AIG_CELLTYPE_INT)
     127             :     {
     128           0 :         eDataType = GDT_Int32;
     129             :     }
     130             :     else
     131             :     {
     132           0 :         eDataType = GDT_Float32;
     133             :     }
     134           9 : }
     135             : 
     136             : /************************************************************************/
     137             : /*                             IReadBlock()                             */
     138             : /************************************************************************/
     139             : 
     140           4 : CPLErr AIGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     141             : 
     142             : {
     143           4 :     AIGDataset *poODS = (AIGDataset *)poDS;
     144             :     GInt32 *panGridRaster;
     145             : 
     146           4 :     if (poODS->psInfo->nCellType == AIG_CELLTYPE_INT)
     147             :     {
     148           4 :         panGridRaster = (GInt32 *)VSIMalloc3(4, nBlockXSize, nBlockYSize);
     149           8 :         if (panGridRaster == nullptr ||
     150           4 :             AIGReadTile(poODS->psInfo, nBlockXOff, nBlockYOff, panGridRaster) !=
     151             :                 CE_None)
     152             :         {
     153           2 :             CPLFree(panGridRaster);
     154           2 :             return CE_Failure;
     155             :         }
     156             : 
     157           2 :         if (eDataType == GDT_Byte)
     158             :         {
     159        2050 :             for (int i = 0; i < nBlockXSize * nBlockYSize; i++)
     160             :             {
     161        2048 :                 if (panGridRaster[i] == ESRI_GRID_NO_DATA)
     162        2042 :                     ((GByte *)pImage)[i] = 255;
     163             :                 else
     164           6 :                     ((GByte *)pImage)[i] = (GByte)panGridRaster[i];
     165             :             }
     166             :         }
     167           0 :         else if (eDataType == GDT_Int16)
     168             :         {
     169           0 :             for (int i = 0; i < nBlockXSize * nBlockYSize; i++)
     170             :             {
     171           0 :                 if (panGridRaster[i] == ESRI_GRID_NO_DATA)
     172           0 :                     ((GInt16 *)pImage)[i] = -32768;
     173             :                 else
     174           0 :                     ((GInt16 *)pImage)[i] = (GInt16)panGridRaster[i];
     175             :             }
     176             :         }
     177             :         else
     178             :         {
     179           0 :             for (int i = 0; i < nBlockXSize * nBlockYSize; i++)
     180           0 :                 ((GInt32 *)pImage)[i] = panGridRaster[i];
     181             :         }
     182             : 
     183           2 :         CPLFree(panGridRaster);
     184             : 
     185           2 :         return CE_None;
     186             :     }
     187             :     else
     188             :     {
     189           0 :         return AIGReadFloatTile(poODS->psInfo, nBlockXOff, nBlockYOff,
     190           0 :                                 (float *)pImage);
     191             :     }
     192             : }
     193             : 
     194             : /************************************************************************/
     195             : /*                           GetDefaultRAT()                            */
     196             : /************************************************************************/
     197             : 
     198           0 : GDALRasterAttributeTable *AIGRasterBand::GetDefaultRAT()
     199             : 
     200             : {
     201           0 :     AIGDataset *poODS = (AIGDataset *)poDS;
     202             : 
     203             :     /* -------------------------------------------------------------------- */
     204             :     /*      Read info raster attribute table, if present.                   */
     205             :     /* -------------------------------------------------------------------- */
     206           0 :     if (!poODS->bHasReadRat)
     207             :     {
     208           0 :         poODS->ReadRAT();
     209           0 :         poODS->bHasReadRat = true;
     210             :     }
     211             : 
     212           0 :     if (poODS->poRAT)
     213           0 :         return poODS->poRAT;
     214             :     else
     215           0 :         return GDALPamRasterBand::GetDefaultRAT();
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /*                             GetMinimum()                             */
     220             : /************************************************************************/
     221             : 
     222           1 : double AIGRasterBand::GetMinimum(int *pbSuccess)
     223             : 
     224             : {
     225           1 :     AIGDataset *poODS = (AIGDataset *)poDS;
     226             : 
     227           1 :     if (pbSuccess != nullptr)
     228           1 :         *pbSuccess = TRUE;
     229             : 
     230           1 :     return poODS->psInfo->dfMin;
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                             GetMaximum()                             */
     235             : /************************************************************************/
     236             : 
     237           1 : double AIGRasterBand::GetMaximum(int *pbSuccess)
     238             : 
     239             : {
     240           1 :     AIGDataset *poODS = (AIGDataset *)poDS;
     241             : 
     242           1 :     if (pbSuccess != nullptr)
     243           1 :         *pbSuccess = TRUE;
     244             : 
     245           1 :     return poODS->psInfo->dfMax;
     246             : }
     247             : 
     248             : /************************************************************************/
     249             : /*                           GetNoDataValue()                           */
     250             : /************************************************************************/
     251             : 
     252           3 : double AIGRasterBand::GetNoDataValue(int *pbSuccess)
     253             : 
     254             : {
     255           3 :     if (pbSuccess != nullptr)
     256           3 :         *pbSuccess = TRUE;
     257             : 
     258           3 :     if (eDataType == GDT_Float32)
     259           0 :         return ESRI_GRID_FLOAT_NO_DATA;
     260             : 
     261           3 :     if (eDataType == GDT_Int16)
     262           0 :         return -32768;
     263             : 
     264           3 :     if (eDataType == GDT_Byte)
     265           3 :         return 255;
     266             : 
     267           0 :     return ESRI_GRID_NO_DATA;
     268             : }
     269             : 
     270             : /************************************************************************/
     271             : /*                       GetColorInterpretation()                       */
     272             : /************************************************************************/
     273             : 
     274           0 : GDALColorInterp AIGRasterBand::GetColorInterpretation()
     275             : 
     276             : {
     277           0 :     AIGDataset *poODS = (AIGDataset *)poDS;
     278             : 
     279           0 :     if (poODS->poCT != nullptr)
     280           0 :         return GCI_PaletteIndex;
     281             : 
     282           0 :     return GDALPamRasterBand::GetColorInterpretation();
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                           GetColorTable()                            */
     287             : /************************************************************************/
     288             : 
     289           2 : GDALColorTable *AIGRasterBand::GetColorTable()
     290             : 
     291             : {
     292           2 :     AIGDataset *poODS = (AIGDataset *)poDS;
     293             : 
     294           2 :     if (poODS->poCT != nullptr)
     295           2 :         return poODS->poCT;
     296             : 
     297           0 :     return GDALPamRasterBand::GetColorTable();
     298             : }
     299             : 
     300             : /************************************************************************/
     301             : /* ==================================================================== */
     302             : /*                            AIGDataset                               */
     303             : /* ==================================================================== */
     304             : /************************************************************************/
     305             : 
     306             : /************************************************************************/
     307             : /*                            AIGDataset()                            */
     308             : /************************************************************************/
     309             : 
     310           9 : AIGDataset::AIGDataset()
     311             :     : psInfo(nullptr), papszPrj(nullptr), poCT(nullptr), bHasReadRat(false),
     312           9 :       poRAT(nullptr)
     313             : {
     314           9 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     315           9 : }
     316             : 
     317             : /************************************************************************/
     318             : /*                           ~AIGDataset()                            */
     319             : /************************************************************************/
     320             : 
     321          18 : AIGDataset::~AIGDataset()
     322             : 
     323             : {
     324           9 :     FlushCache(true);
     325           9 :     CSLDestroy(papszPrj);
     326           9 :     if (psInfo != nullptr)
     327           9 :         AIGClose(psInfo);
     328             : 
     329           9 :     if (poCT != nullptr)
     330           7 :         delete poCT;
     331             : 
     332           9 :     if (poRAT != nullptr)
     333           0 :         delete poRAT;
     334          18 : }
     335             : 
     336             : /************************************************************************/
     337             : /*                            GetFileList()                             */
     338             : /************************************************************************/
     339             : 
     340           2 : char **AIGDataset::GetFileList()
     341             : 
     342             : {
     343           2 :     char **papszFileList = GDALPamDataset::GetFileList();
     344             : 
     345             :     // Add in all files in the cover directory.
     346           2 :     char **papszCoverFiles = VSIReadDir(GetDescription());
     347             : 
     348          21 :     for (int i = 0; papszCoverFiles != nullptr && papszCoverFiles[i] != nullptr;
     349             :          i++)
     350             :     {
     351          19 :         if (EQUAL(papszCoverFiles[i], ".") || EQUAL(papszCoverFiles[i], ".."))
     352           4 :             continue;
     353             : 
     354          15 :         papszFileList = CSLAddString(
     355             :             papszFileList,
     356          15 :             CPLFormFilename(GetDescription(), papszCoverFiles[i], nullptr));
     357             :     }
     358           2 :     CSLDestroy(papszCoverFiles);
     359             : 
     360           2 :     return papszFileList;
     361             : }
     362             : 
     363             : /************************************************************************/
     364             : /*                          AIGErrorHandlerVATOpen()                    */
     365             : /************************************************************************/
     366             : 
     367             : class AIGErrorDescription
     368             : {
     369             :   public:
     370             :     CPLErr eErr;
     371             :     CPLErrorNum no;
     372             :     CPLString osMsg;
     373             : };
     374             : 
     375           0 : static void CPL_STDCALL AIGErrorHandlerVATOpen(CPLErr eErr, CPLErrorNum no,
     376             :                                                const char *msg)
     377             : {
     378             :     std::vector<AIGErrorDescription> *paoErrors =
     379           0 :         (std::vector<AIGErrorDescription> *)CPLGetErrorHandlerUserData();
     380           0 :     if (STARTS_WITH_CI(msg, "EOF encountered in") &&
     381           0 :         strstr(msg, "../info/arc.dir") != nullptr)
     382           0 :         return;
     383           0 :     if (STARTS_WITH_CI(msg, "Failed to open table "))
     384           0 :         return;
     385           0 :     AIGErrorDescription oError;
     386           0 :     oError.eErr = eErr;
     387           0 :     oError.no = no;
     388           0 :     oError.osMsg = msg;
     389           0 :     paoErrors->push_back(oError);
     390             : }
     391             : 
     392             : /************************************************************************/
     393             : /*                              ReadRAT()                               */
     394             : /************************************************************************/
     395             : 
     396           0 : void AIGDataset::ReadRAT()
     397             : 
     398             : {
     399             :     /* -------------------------------------------------------------------- */
     400             :     /*      Check if we have an associated info directory.  If not          */
     401             :     /*      return quietly.                                                 */
     402             :     /* -------------------------------------------------------------------- */
     403           0 :     CPLString osInfoPath, osTableName;
     404             :     VSIStatBufL sStatBuf;
     405             : 
     406           0 :     osInfoPath = psInfo->pszCoverName;
     407           0 :     osInfoPath += "/../info";
     408             : 
     409           0 :     if (VSIStatL(osInfoPath, &sStatBuf) != 0)
     410             :     {
     411           0 :         CPLDebug("AIG", "No associated info directory at: %s, skip RAT.",
     412             :                  osInfoPath.c_str());
     413           0 :         return;
     414             :     }
     415             : 
     416           0 :     osInfoPath += "/";
     417             : 
     418             :     /* -------------------------------------------------------------------- */
     419             :     /*      Attempt to open the VAT table associated with this coverage.    */
     420             :     /* -------------------------------------------------------------------- */
     421           0 :     osTableName = CPLGetFilename(psInfo->pszCoverName);
     422           0 :     osTableName += ".VAT";
     423             : 
     424             :     /* Turn off errors that can be triggered if the info has no VAT */
     425             :     /* table related with this coverage */
     426           0 :     std::vector<AIGErrorDescription> aoErrors;
     427           0 :     CPLPushErrorHandlerEx(AIGErrorHandlerVATOpen, &aoErrors);
     428             : 
     429           0 :     AVCBinFile *psFile = AVCBinReadOpen(
     430             :         osInfoPath, osTableName, AVCCoverTypeUnknown, AVCFileTABLE, nullptr);
     431           0 :     CPLPopErrorHandler();
     432             : 
     433             :     /* Emit other errors */
     434           0 :     std::vector<AIGErrorDescription>::const_iterator oIter;
     435           0 :     for (oIter = aoErrors.begin(); oIter != aoErrors.end(); ++oIter)
     436             :     {
     437           0 :         const AIGErrorDescription &oError = *oIter;
     438           0 :         CPLError(oError.eErr, oError.no, "%s", oError.osMsg.c_str());
     439             :     }
     440             : 
     441           0 :     CPLErrorReset();
     442           0 :     if (psFile == nullptr)
     443           0 :         return;
     444             : 
     445           0 :     AVCTableDef *psTableDef = psFile->hdr.psTableDef;
     446             : 
     447             :     /* -------------------------------------------------------------------- */
     448             :     /*      Setup columns in corresponding RAT.                             */
     449             :     /* -------------------------------------------------------------------- */
     450           0 :     poRAT = new GDALDefaultRasterAttributeTable();
     451             : 
     452           0 :     for (int iField = 0; iField < psTableDef->numFields; iField++)
     453             :     {
     454           0 :         AVCFieldInfo *psFDef = psTableDef->pasFieldDef + iField;
     455           0 :         GDALRATFieldUsage eFUsage = GFU_Generic;
     456           0 :         GDALRATFieldType eFType = GFT_String;
     457             : 
     458           0 :         CPLString osFName = psFDef->szName;
     459           0 :         osFName.Trim();
     460             : 
     461           0 :         if (EQUAL(osFName, "VALUE"))
     462           0 :             eFUsage = GFU_MinMax;
     463           0 :         else if (EQUAL(osFName, "COUNT"))
     464           0 :             eFUsage = GFU_PixelCount;
     465             : 
     466           0 :         if (psFDef->nType1 * 10 == AVC_FT_BININT)
     467           0 :             eFType = GFT_Integer;
     468           0 :         else if (psFDef->nType1 * 10 == AVC_FT_BINFLOAT)
     469           0 :             eFType = GFT_Real;
     470             : 
     471           0 :         poRAT->CreateColumn(osFName, eFType, eFUsage);
     472             :     }
     473             : 
     474             :     /* -------------------------------------------------------------------- */
     475             :     /*      Process all records into RAT.                                   */
     476             :     /* -------------------------------------------------------------------- */
     477           0 :     AVCField *pasFields = nullptr;
     478           0 :     int iRecord = 0;
     479             : 
     480           0 :     while ((pasFields = AVCBinReadNextTableRec(psFile)) != nullptr)
     481             :     {
     482           0 :         iRecord++;
     483             : 
     484           0 :         for (int iField = 0; iField < psTableDef->numFields; iField++)
     485             :         {
     486           0 :             switch (psTableDef->pasFieldDef[iField].nType1 * 10)
     487             :             {
     488           0 :                 case AVC_FT_DATE:
     489             :                 case AVC_FT_FIXINT:
     490             :                 case AVC_FT_CHAR:
     491             :                 case AVC_FT_FIXNUM:
     492             :                 {
     493             :                     // XXX - I bet mloskot would like to see const_cast +
     494             :                     // static_cast :-)
     495           0 :                     const char *pszTmp =
     496           0 :                         (const char *)(pasFields[iField].pszStr);
     497           0 :                     CPLString osStrValue(pszTmp);
     498           0 :                     poRAT->SetValue(iRecord - 1, iField, osStrValue.Trim());
     499             :                 }
     500           0 :                 break;
     501             : 
     502           0 :                 case AVC_FT_BININT:
     503           0 :                     if (psTableDef->pasFieldDef[iField].nSize == 4)
     504           0 :                         poRAT->SetValue(iRecord - 1, iField,
     505           0 :                                         pasFields[iField].nInt32);
     506             :                     else
     507           0 :                         poRAT->SetValue(iRecord - 1, iField,
     508           0 :                                         pasFields[iField].nInt16);
     509           0 :                     break;
     510             : 
     511           0 :                 case AVC_FT_BINFLOAT:
     512           0 :                     if (psTableDef->pasFieldDef[iField].nSize == 4)
     513           0 :                         poRAT->SetValue(iRecord - 1, iField,
     514           0 :                                         pasFields[iField].fFloat);
     515             :                     else
     516           0 :                         poRAT->SetValue(iRecord - 1, iField,
     517           0 :                                         pasFields[iField].dDouble);
     518           0 :                     break;
     519             :             }
     520             :         }
     521             :     }
     522             : 
     523             :     /* -------------------------------------------------------------------- */
     524             :     /*      Cleanup                                                         */
     525             :     /* -------------------------------------------------------------------- */
     526             : 
     527           0 :     AVCBinReadClose(psFile);
     528             : 
     529             :     /* Workaround against #2447 and #3031, to avoid binding languages */
     530             :     /* not being able to open the dataset */
     531           0 :     CPLErrorReset();
     532             : }
     533             : 
     534             : /************************************************************************/
     535             : /*                                Open()                                */
     536             : /************************************************************************/
     537             : 
     538       33994 : GDALDataset *AIGDataset::Open(GDALOpenInfo *poOpenInfo)
     539             : 
     540             : {
     541             :     /* -------------------------------------------------------------------- */
     542             :     /*      If the pass name ends in .adf assume a file within the          */
     543             :     /*      coverage has been selected, and strip that off the coverage     */
     544             :     /*      name.                                                           */
     545             :     /* -------------------------------------------------------------------- */
     546       67988 :     CPLString osCoverName;
     547             : 
     548       33994 :     osCoverName = poOpenInfo->pszFilename;
     549       67587 :     if (osCoverName.size() > 4 &&
     550       33593 :         EQUAL(osCoverName.c_str() + osCoverName.size() - 4, ".adf"))
     551             :     {
     552           1 :         osCoverName = CPLGetDirname(poOpenInfo->pszFilename);
     553           1 :         if (osCoverName == "")
     554           0 :             osCoverName = ".";
     555             :     }
     556             : 
     557             :     /* -------------------------------------------------------------------- */
     558             :     /*      Otherwise verify we were already given a directory.             */
     559             :     /* -------------------------------------------------------------------- */
     560       33993 :     else if (!poOpenInfo->bIsDirectory)
     561             :     {
     562       33628 :         return nullptr;
     563             :     }
     564             : 
     565             :     /* -------------------------------------------------------------------- */
     566             :     /*      Verify that a few of the "standard" files are available.        */
     567             :     /* -------------------------------------------------------------------- */
     568             :     VSIStatBufL sStatBuf;
     569         732 :     CPLString osTestName;
     570             : 
     571         366 :     osTestName.Printf("%s/hdr.adf", osCoverName.c_str());
     572         366 :     if (VSIStatL(osTestName, &sStatBuf) != 0)
     573             :     {
     574         360 :         osTestName.Printf("%s/HDR.ADF", osCoverName.c_str());
     575         360 :         if (VSIStatL(osTestName, &sStatBuf) != 0)
     576         357 :             return nullptr;
     577             :     }
     578             : 
     579             :     /* -------------------------------------------------------------------- */
     580             :     /*      Confirm we have at least one raster data file.  These can be    */
     581             :     /*      sparse so we don't require particular ones to exists but if     */
     582             :     /*      there are none this is likely not a grid.                       */
     583             :     /* -------------------------------------------------------------------- */
     584           9 :     char **papszFileList = VSIReadDir(osCoverName);
     585           9 :     bool bGotOne = false;
     586             : 
     587           9 :     if (papszFileList == nullptr)
     588             :     {
     589             :         /* Useful when reading from /vsicurl/ on servers that don't */
     590             :         /* return a file list */
     591             :         /* such as
     592             :          * /vsicurl/http://eros.usgs.gov/archive/nslrsda/GeoTowns/NLCD/89110458
     593             :          */
     594             :         do
     595             :         {
     596           0 :             osTestName.Printf("%s/W001001.ADF", osCoverName.c_str());
     597           0 :             if (VSIStatL(osTestName, &sStatBuf) == 0)
     598             :             {
     599           0 :                 bGotOne = true;
     600           0 :                 break;
     601             :             }
     602             : 
     603           0 :             osTestName.Printf("%s/w001001.adf", osCoverName.c_str());
     604           0 :             if (VSIStatL(osTestName, &sStatBuf) == 0)
     605             :             {
     606           0 :                 bGotOne = true;
     607           0 :                 break;
     608             :             }
     609             :         } while (false);
     610             :     }
     611             : 
     612          80 :     for (int iFile = 0; papszFileList != nullptr &&
     613          80 :                         papszFileList[iFile] != nullptr && !bGotOne;
     614             :          iFile++)
     615             :     {
     616          71 :         if (strlen(papszFileList[iFile]) != 11)
     617          62 :             continue;
     618             : 
     619             :         // looking for something like w001001.adf or z001013.adf
     620           9 :         if (papszFileList[iFile][0] != 'w' && papszFileList[iFile][0] != 'W' &&
     621           0 :             papszFileList[iFile][0] != 'z' && papszFileList[iFile][0] != 'Z')
     622           0 :             continue;
     623             : 
     624           9 :         if (!STARTS_WITH(papszFileList[iFile] + 1, "0010"))
     625           0 :             continue;
     626             : 
     627           9 :         if (!EQUAL(papszFileList[iFile] + 7, ".adf"))
     628           0 :             continue;
     629             : 
     630           9 :         bGotOne = true;
     631             :     }
     632           9 :     CSLDestroy(papszFileList);
     633             : 
     634           9 :     if (!bGotOne)
     635           0 :         return nullptr;
     636             : 
     637             :     /* -------------------------------------------------------------------- */
     638             :     /*      Open the file.                                                  */
     639             :     /* -------------------------------------------------------------------- */
     640           9 :     AIGInfo_t *psInfo = AIGOpen(osCoverName.c_str(), "r");
     641             : 
     642           9 :     if (psInfo == nullptr)
     643             :     {
     644           0 :         CPLErrorReset();
     645           0 :         return nullptr;
     646             :     }
     647             : 
     648             :     /* -------------------------------------------------------------------- */
     649             :     /*      Confirm the requested access is supported.                      */
     650             :     /* -------------------------------------------------------------------- */
     651           9 :     if (poOpenInfo->eAccess == GA_Update)
     652             :     {
     653           0 :         AIGClose(psInfo);
     654           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     655             :                  "The AIG driver does not support update access to existing"
     656             :                  " datasets.\n");
     657           0 :         return nullptr;
     658             :     }
     659             :     /* -------------------------------------------------------------------- */
     660             :     /*      Create a corresponding GDALDataset.                             */
     661             :     /* -------------------------------------------------------------------- */
     662           9 :     AIGDataset *poDS = new AIGDataset();
     663             : 
     664           9 :     poDS->psInfo = psInfo;
     665             : 
     666             :     /* -------------------------------------------------------------------- */
     667             :     /*      Try to read a color table (.clr).  It seems it is legal to      */
     668             :     /*      have more than one so we just use the first one found.          */
     669             :     /* -------------------------------------------------------------------- */
     670           9 :     char **papszFiles = VSIReadDir(psInfo->pszCoverName);
     671          18 :     CPLString osClrFilename;
     672           9 :     CPLString osCleanPath = CPLCleanTrailingSlash(psInfo->pszCoverName);
     673             : 
     674             :     // first check for any .clr in coverage dir.
     675          79 :     for (int iFile = 0; papszFiles != nullptr && papszFiles[iFile] != nullptr;
     676             :          iFile++)
     677             :     {
     678         145 :         if (!EQUAL(CPLGetExtension(papszFiles[iFile]), "clr") &&
     679          70 :             !EQUAL(CPLGetExtension(papszFiles[iFile]), "CLR"))
     680          70 :             continue;
     681             : 
     682             :         osClrFilename =
     683           5 :             CPLFormFilename(psInfo->pszCoverName, papszFiles[iFile], nullptr);
     684           5 :         break;
     685             :     }
     686             : 
     687           9 :     CSLDestroy(papszFiles);
     688             : 
     689             :     // Look in parent if we don't find a .clr in the coverage dir.
     690           9 :     if (osClrFilename.empty())
     691             :     {
     692           8 :         CPLString osTestClrFilename;
     693             :         osTestClrFilename.Printf("%s/../%s.clr", psInfo->pszCoverName,
     694           4 :                                  CPLGetFilename(osCleanPath));
     695             : 
     696           4 :         if (VSIStatL(osTestClrFilename, &sStatBuf) != 0)
     697             :         {
     698             :             osTestClrFilename.Printf("%s/../%s.CLR", psInfo->pszCoverName,
     699           4 :                                      CPLGetFilename(osCleanPath));
     700             : 
     701           4 :             if (!VSIStatL(osTestClrFilename, &sStatBuf))
     702           2 :                 osClrFilename = std::move(osTestClrFilename);
     703             :         }
     704             :         else
     705           0 :             osClrFilename = std::move(osTestClrFilename);
     706             :     }
     707             : 
     708           9 :     if (!osClrFilename.empty())
     709           7 :         poDS->TranslateColorTable(osClrFilename);
     710             : 
     711             :     /* -------------------------------------------------------------------- */
     712             :     /*      Establish raster info.                                          */
     713             :     /* -------------------------------------------------------------------- */
     714           9 :     poDS->nRasterXSize = psInfo->nPixels;
     715           9 :     poDS->nRasterYSize = psInfo->nLines;
     716           9 :     poDS->nBands = 1;
     717             : 
     718             :     /* -------------------------------------------------------------------- */
     719             :     /*      Create band information objects.                                */
     720             :     /* -------------------------------------------------------------------- */
     721           9 :     poDS->SetBand(1, new AIGRasterBand(poDS, 1));
     722             : 
     723             :     /* -------------------------------------------------------------------- */
     724             :     /*      Try to read projection file.                                    */
     725             :     /* -------------------------------------------------------------------- */
     726             :     const char *pszPrjFilename =
     727           9 :         CPLFormCIFilename(psInfo->pszCoverName, "prj", "adf");
     728           9 :     if (VSIStatL(pszPrjFilename, &sStatBuf) == 0)
     729             :     {
     730          18 :         OGRSpatialReference oSRS;
     731           9 :         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     732             : 
     733           9 :         poDS->papszPrj = CSLLoad(pszPrjFilename);
     734             : 
     735           9 :         if (oSRS.importFromESRI(poDS->papszPrj) == OGRERR_NONE)
     736             :         {
     737             :             // If geographic values are in seconds, we must transform.
     738             :             // Is there a code for minutes too?
     739          10 :             if (oSRS.IsGeographic() &&
     740          10 :                 EQUAL(OSR_GDS(poDS->papszPrj, "Units", ""), "DS"))
     741             :             {
     742           0 :                 psInfo->dfLLX /= 3600.0;
     743           0 :                 psInfo->dfURY /= 3600.0;
     744           0 :                 psInfo->dfCellSizeX /= 3600.0;
     745           0 :                 psInfo->dfCellSizeY /= 3600.0;
     746             :             }
     747             : 
     748           9 :             poDS->m_oSRS = std::move(oSRS);
     749             :         }
     750             :     }
     751             : 
     752             :     /* -------------------------------------------------------------------- */
     753             :     /*      Initialize any PAM information.                                 */
     754             :     /* -------------------------------------------------------------------- */
     755           9 :     poDS->SetDescription(psInfo->pszCoverName);
     756           9 :     poDS->TryLoadXML();
     757             : 
     758             :     /* -------------------------------------------------------------------- */
     759             :     /*      Open overviews.                                                 */
     760             :     /* -------------------------------------------------------------------- */
     761           9 :     poDS->oOvManager.Initialize(poDS, psInfo->pszCoverName);
     762             : 
     763           9 :     return poDS;
     764             : }
     765             : 
     766             : /************************************************************************/
     767             : /*                          GetGeoTransform()                           */
     768             : /************************************************************************/
     769             : 
     770           1 : CPLErr AIGDataset::GetGeoTransform(double *padfTransform)
     771             : 
     772             : {
     773           1 :     padfTransform[0] = psInfo->dfLLX;
     774           1 :     padfTransform[1] = psInfo->dfCellSizeX;
     775           1 :     padfTransform[2] = 0;
     776             : 
     777           1 :     padfTransform[3] = psInfo->dfURY;
     778           1 :     padfTransform[4] = 0;
     779           1 :     padfTransform[5] = -psInfo->dfCellSizeY;
     780             : 
     781           1 :     return CE_None;
     782             : }
     783             : 
     784             : /************************************************************************/
     785             : /*                          GetSpatialRef()                             */
     786             : /************************************************************************/
     787             : 
     788           1 : const OGRSpatialReference *AIGDataset::GetSpatialRef() const
     789             : 
     790             : {
     791           1 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     792             : }
     793             : 
     794             : /************************************************************************/
     795             : /*                        TranslateColorTable()                         */
     796             : /************************************************************************/
     797             : 
     798           7 : void AIGDataset::TranslateColorTable(const char *pszClrFilename)
     799             : 
     800             : {
     801           7 :     char **papszClrLines = CSLLoad(pszClrFilename);
     802           7 :     if (papszClrLines == nullptr)
     803           0 :         return;
     804             : 
     805           7 :     poCT = new GDALColorTable();
     806             : 
     807        1813 :     for (int iLine = 0; papszClrLines[iLine] != nullptr; iLine++)
     808             :     {
     809        1806 :         char **papszTokens = CSLTokenizeString(papszClrLines[iLine]);
     810             : 
     811        1806 :         if (CSLCount(papszTokens) >= 4 && papszTokens[0][0] != '#')
     812             :         {
     813             :             int nIndex;
     814             :             GDALColorEntry sEntry;
     815             : 
     816        1792 :             nIndex = atoi(papszTokens[0]);
     817        1792 :             sEntry.c1 = (short)atoi(papszTokens[1]);
     818        1792 :             sEntry.c2 = (short)atoi(papszTokens[2]);
     819        1792 :             sEntry.c3 = (short)atoi(papszTokens[3]);
     820        1792 :             sEntry.c4 = 255;
     821             : 
     822        1792 :             if ((nIndex < 0 || nIndex > 33000) ||
     823        1792 :                 (sEntry.c1 < 0 || sEntry.c1 > 255) ||
     824        1792 :                 (sEntry.c2 < 0 || sEntry.c2 > 255) ||
     825        1792 :                 (sEntry.c3 < 0 || sEntry.c3 > 255))
     826             :             {
     827           0 :                 CSLDestroy(papszTokens);
     828           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     829             :                          "Color table entry appears to be corrupt, skipping "
     830             :                          "the rest. ");
     831           0 :                 break;
     832             :             }
     833             : 
     834        1792 :             poCT->SetColorEntry(nIndex, &sEntry);
     835             :         }
     836             : 
     837        1806 :         CSLDestroy(papszTokens);
     838             :     }
     839             : 
     840           7 :     CSLDestroy(papszClrLines);
     841             : }
     842             : 
     843             : /************************************************************************/
     844             : /*                              OSR_GDS()                               */
     845             : /************************************************************************/
     846             : 
     847           1 : static CPLString OSR_GDS(char **papszNV, const char *pszField,
     848             :                          const char *pszDefaultValue)
     849             : 
     850             : {
     851           1 :     if (papszNV == nullptr || papszNV[0] == nullptr)
     852           0 :         return pszDefaultValue;
     853             : 
     854           1 :     int iLine = 0;
     855           4 :     for (; papszNV[iLine] != nullptr &&
     856           4 :            !EQUALN(papszNV[iLine], pszField, strlen(pszField));
     857             :          iLine++)
     858             :     {
     859             :     }
     860             : 
     861           1 :     if (papszNV[iLine] == nullptr)
     862           0 :         return pszDefaultValue;
     863             :     else
     864             :     {
     865           2 :         CPLString osResult;
     866           1 :         char **papszTokens = CSLTokenizeString(papszNV[iLine]);
     867             : 
     868           1 :         if (CSLCount(papszTokens) > 1)
     869           1 :             osResult = papszTokens[1];
     870             :         else
     871           0 :             osResult = pszDefaultValue;
     872             : 
     873           1 :         CSLDestroy(papszTokens);
     874           1 :         return osResult;
     875             :     }
     876             : }
     877             : 
     878             : /************************************************************************/
     879             : /*                             AIGRename()                              */
     880             : /*                                                                      */
     881             : /*      Custom renamer for AIG dataset.                                 */
     882             : /************************************************************************/
     883             : 
     884           0 : static CPLErr AIGRename(const char *pszNewName, const char *pszOldName)
     885             : 
     886             : {
     887             :     /* -------------------------------------------------------------------- */
     888             :     /*      Make sure we are talking about paths to the coverage            */
     889             :     /*      directory.                                                      */
     890             :     /* -------------------------------------------------------------------- */
     891           0 :     CPLString osOldPath, osNewPath;
     892             : 
     893           0 :     if (strlen(CPLGetExtension(pszNewName)) > 0)
     894           0 :         osNewPath = CPLGetPath(pszNewName);
     895             :     else
     896           0 :         osNewPath = pszNewName;
     897             : 
     898           0 :     if (strlen(CPLGetExtension(pszOldName)) > 0)
     899           0 :         osOldPath = CPLGetPath(pszOldName);
     900             :     else
     901           0 :         osOldPath = pszOldName;
     902             : 
     903             :     /* -------------------------------------------------------------------- */
     904             :     /*      Get file list.                                                  */
     905             :     /* -------------------------------------------------------------------- */
     906             : 
     907           0 :     GDALDatasetH hDS = GDALOpen(osOldPath, GA_ReadOnly);
     908           0 :     if (hDS == nullptr)
     909           0 :         return CE_Failure;
     910             : 
     911           0 :     char **papszFileList = GDALGetFileList(hDS);
     912           0 :     GDALClose(hDS);
     913             : 
     914           0 :     if (papszFileList == nullptr)
     915           0 :         return CE_Failure;
     916             : 
     917             :     /* -------------------------------------------------------------------- */
     918             :     /*      Work out the corresponding new names.                           */
     919             :     /* -------------------------------------------------------------------- */
     920           0 :     char **papszNewFileList = nullptr;
     921             : 
     922           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
     923             :     {
     924           0 :         CPLString osNewFilename;
     925             : 
     926           0 :         if (!EQUALN(papszFileList[i], osOldPath, osOldPath.size()))
     927             :         {
     928           0 :             CPLAssert(false);
     929             :             return CE_Failure;
     930             :         }
     931             : 
     932           0 :         osNewFilename = osNewPath + (papszFileList[i] + osOldPath.size());
     933             : 
     934           0 :         papszNewFileList = CSLAddString(papszNewFileList, osNewFilename);
     935             :     }
     936             : 
     937             :     /* -------------------------------------------------------------------- */
     938             :     /*      Try renaming the directory.                                     */
     939             :     /* -------------------------------------------------------------------- */
     940           0 :     if (VSIRename(osNewPath, osOldPath) != 0)
     941             :     {
     942           0 :         if (VSIMkdir(osNewPath, 0777) != 0)
     943             :         {
     944           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     945             :                      "Unable to create directory %s:\n%s", osNewPath.c_str(),
     946           0 :                      VSIStrerror(errno));
     947           0 :             CSLDestroy(papszNewFileList);
     948           0 :             return CE_Failure;
     949             :         }
     950             :     }
     951             : 
     952             :     /* -------------------------------------------------------------------- */
     953             :     /*      Copy/rename any remaining files.                                */
     954             :     /* -------------------------------------------------------------------- */
     955             :     VSIStatBufL sStatBuf;
     956             : 
     957           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
     958             :     {
     959           0 :         if (VSIStatL(papszFileList[i], &sStatBuf) == 0 &&
     960           0 :             VSI_ISREG(sStatBuf.st_mode))
     961             :         {
     962           0 :             if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
     963             :             {
     964           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     965           0 :                          "Unable to move %s to %s:\n%s", papszFileList[i],
     966           0 :                          papszNewFileList[i], VSIStrerror(errno));
     967           0 :                 CSLDestroy(papszNewFileList);
     968           0 :                 return CE_Failure;
     969             :             }
     970             :         }
     971             :     }
     972             : 
     973           0 :     if (VSIStatL(osOldPath, &sStatBuf) == 0)
     974             :     {
     975           0 :         if (CPLUnlinkTree(osOldPath) != 0)
     976             :         {
     977           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     978             :                      "Unable to cleanup old path.");
     979             :         }
     980             :     }
     981             : 
     982           0 :     CSLDestroy(papszFileList);
     983           0 :     CSLDestroy(papszNewFileList);
     984           0 :     return CE_None;
     985             : }
     986             : 
     987             : /************************************************************************/
     988             : /*                             AIGDelete()                              */
     989             : /*                                                                      */
     990             : /*      Custom dataset deleter for AIG dataset.                         */
     991             : /************************************************************************/
     992             : 
     993           0 : static CPLErr AIGDelete(const char *pszDatasetname)
     994             : 
     995             : {
     996             :     /* -------------------------------------------------------------------- */
     997             :     /*      Get file list.                                                  */
     998             :     /* -------------------------------------------------------------------- */
     999           0 :     GDALDatasetH hDS = GDALOpen(pszDatasetname, GA_ReadOnly);
    1000           0 :     if (hDS == nullptr)
    1001           0 :         return CE_Failure;
    1002             : 
    1003           0 :     char **papszFileList = GDALGetFileList(hDS);
    1004           0 :     GDALClose(hDS);
    1005             : 
    1006           0 :     if (papszFileList == nullptr)
    1007           0 :         return CE_Failure;
    1008             : 
    1009             :     /* -------------------------------------------------------------------- */
    1010             :     /*      Delete all regular files.                                       */
    1011             :     /* -------------------------------------------------------------------- */
    1012           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
    1013             :     {
    1014             :         VSIStatBufL sStatBuf;
    1015           0 :         if (VSIStatL(papszFileList[i], &sStatBuf) == 0 &&
    1016           0 :             VSI_ISREG(sStatBuf.st_mode))
    1017             :         {
    1018           0 :             if (VSIUnlink(papszFileList[i]) != 0)
    1019             :             {
    1020           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1021           0 :                          "Unable to delete '%s':\n%s", papszFileList[i],
    1022           0 :                          VSIStrerror(errno));
    1023           0 :                 return CE_Failure;
    1024             :             }
    1025             :         }
    1026             :     }
    1027             : 
    1028             :     /* -------------------------------------------------------------------- */
    1029             :     /*      Delete directories.                                             */
    1030             :     /* -------------------------------------------------------------------- */
    1031           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
    1032             :     {
    1033             :         VSIStatBufL sStatBuf;
    1034           0 :         if (VSIStatL(papszFileList[i], &sStatBuf) == 0 &&
    1035           0 :             VSI_ISDIR(sStatBuf.st_mode))
    1036             :         {
    1037           0 :             if (CPLUnlinkTree(papszFileList[i]) != 0)
    1038           0 :                 return CE_Failure;
    1039             :         }
    1040             :     }
    1041             : 
    1042           0 :     return CE_None;
    1043             : }
    1044             : 
    1045             : /************************************************************************/
    1046             : /*                          GDALRegister_AIG()                          */
    1047             : /************************************************************************/
    1048             : 
    1049        1511 : void GDALRegister_AIGrid()
    1050             : 
    1051             : {
    1052        1511 :     if (GDALGetDriverByName("AIG") != nullptr)
    1053         295 :         return;
    1054             : 
    1055        1216 :     GDALDriver *poDriver = new GDALDriver();
    1056             : 
    1057        1216 :     poDriver->SetDescription("AIG");
    1058        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1059        1216 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Arc/Info Binary Grid");
    1060        1216 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/aig.html");
    1061        1216 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1062             : 
    1063        1216 :     poDriver->pfnOpen = AIGDataset::Open;
    1064             : 
    1065        1216 :     poDriver->pfnRename = AIGRename;
    1066        1216 :     poDriver->pfnDelete = AIGDelete;
    1067             : 
    1068        1216 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1069             : }

Generated by: LCOV version 1.14