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

Generated by: LCOV version 1.14