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-11-21 22:18:42 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          15 :             CPLFormFilename(GetDescription(), papszCoverFiles[i], nullptr));
     341             :     }
     342           2 :     CSLDestroy(papszCoverFiles);
     343             : 
     344           2 :     return papszFileList;
     345             : }
     346             : 
     347             : /************************************************************************/
     348             : /*                          AIGErrorHandlerVATOpen()                    */
     349             : /************************************************************************/
     350             : 
     351             : class AIGErrorDescription
     352             : {
     353             :   public:
     354             :     CPLErr eErr;
     355             :     CPLErrorNum no;
     356             :     CPLString osMsg;
     357             : };
     358             : 
     359           0 : static void CPL_STDCALL AIGErrorHandlerVATOpen(CPLErr eErr, CPLErrorNum no,
     360             :                                                const char *msg)
     361             : {
     362             :     std::vector<AIGErrorDescription> *paoErrors =
     363           0 :         (std::vector<AIGErrorDescription> *)CPLGetErrorHandlerUserData();
     364           0 :     if (STARTS_WITH_CI(msg, "EOF encountered in") &&
     365           0 :         strstr(msg, "../info/arc.dir") != nullptr)
     366           0 :         return;
     367           0 :     if (STARTS_WITH_CI(msg, "Failed to open table "))
     368           0 :         return;
     369           0 :     AIGErrorDescription oError;
     370           0 :     oError.eErr = eErr;
     371           0 :     oError.no = no;
     372           0 :     oError.osMsg = msg;
     373           0 :     paoErrors->push_back(oError);
     374             : }
     375             : 
     376             : /************************************************************************/
     377             : /*                              ReadRAT()                               */
     378             : /************************************************************************/
     379             : 
     380           0 : void AIGDataset::ReadRAT()
     381             : 
     382             : {
     383             :     /* -------------------------------------------------------------------- */
     384             :     /*      Check if we have an associated info directory.  If not          */
     385             :     /*      return quietly.                                                 */
     386             :     /* -------------------------------------------------------------------- */
     387           0 :     CPLString osInfoPath, osTableName;
     388             :     VSIStatBufL sStatBuf;
     389             : 
     390           0 :     osInfoPath = psInfo->pszCoverName;
     391           0 :     osInfoPath += "/../info";
     392             : 
     393           0 :     if (VSIStatL(osInfoPath, &sStatBuf) != 0)
     394             :     {
     395           0 :         CPLDebug("AIG", "No associated info directory at: %s, skip RAT.",
     396             :                  osInfoPath.c_str());
     397           0 :         return;
     398             :     }
     399             : 
     400           0 :     osInfoPath += "/";
     401             : 
     402             :     /* -------------------------------------------------------------------- */
     403             :     /*      Attempt to open the VAT table associated with this coverage.    */
     404             :     /* -------------------------------------------------------------------- */
     405           0 :     osTableName = CPLGetFilename(psInfo->pszCoverName);
     406           0 :     osTableName += ".VAT";
     407             : 
     408             :     /* Turn off errors that can be triggered if the info has no VAT */
     409             :     /* table related with this coverage */
     410           0 :     std::vector<AIGErrorDescription> aoErrors;
     411           0 :     CPLPushErrorHandlerEx(AIGErrorHandlerVATOpen, &aoErrors);
     412             : 
     413           0 :     AVCBinFile *psFile = AVCBinReadOpen(
     414             :         osInfoPath, osTableName, AVCCoverTypeUnknown, AVCFileTABLE, nullptr);
     415           0 :     CPLPopErrorHandler();
     416             : 
     417             :     /* Emit other errors */
     418           0 :     std::vector<AIGErrorDescription>::const_iterator oIter;
     419           0 :     for (oIter = aoErrors.begin(); oIter != aoErrors.end(); ++oIter)
     420             :     {
     421           0 :         const AIGErrorDescription &oError = *oIter;
     422           0 :         CPLError(oError.eErr, oError.no, "%s", oError.osMsg.c_str());
     423             :     }
     424             : 
     425           0 :     CPLErrorReset();
     426           0 :     if (psFile == nullptr)
     427           0 :         return;
     428             : 
     429           0 :     AVCTableDef *psTableDef = psFile->hdr.psTableDef;
     430             : 
     431             :     /* -------------------------------------------------------------------- */
     432             :     /*      Setup columns in corresponding RAT.                             */
     433             :     /* -------------------------------------------------------------------- */
     434           0 :     poRAT = new GDALDefaultRasterAttributeTable();
     435             : 
     436           0 :     for (int iField = 0; iField < psTableDef->numFields; iField++)
     437             :     {
     438           0 :         AVCFieldInfo *psFDef = psTableDef->pasFieldDef + iField;
     439           0 :         GDALRATFieldUsage eFUsage = GFU_Generic;
     440           0 :         GDALRATFieldType eFType = GFT_String;
     441             : 
     442           0 :         CPLString osFName = psFDef->szName;
     443           0 :         osFName.Trim();
     444             : 
     445           0 :         if (EQUAL(osFName, "VALUE"))
     446           0 :             eFUsage = GFU_MinMax;
     447           0 :         else if (EQUAL(osFName, "COUNT"))
     448           0 :             eFUsage = GFU_PixelCount;
     449             : 
     450           0 :         if (psFDef->nType1 * 10 == AVC_FT_BININT)
     451           0 :             eFType = GFT_Integer;
     452           0 :         else if (psFDef->nType1 * 10 == AVC_FT_BINFLOAT)
     453           0 :             eFType = GFT_Real;
     454             : 
     455           0 :         poRAT->CreateColumn(osFName, eFType, eFUsage);
     456             :     }
     457             : 
     458             :     /* -------------------------------------------------------------------- */
     459             :     /*      Process all records into RAT.                                   */
     460             :     /* -------------------------------------------------------------------- */
     461           0 :     AVCField *pasFields = nullptr;
     462           0 :     int iRecord = 0;
     463             : 
     464           0 :     while ((pasFields = AVCBinReadNextTableRec(psFile)) != nullptr)
     465             :     {
     466           0 :         iRecord++;
     467             : 
     468           0 :         for (int iField = 0; iField < psTableDef->numFields; iField++)
     469             :         {
     470           0 :             switch (psTableDef->pasFieldDef[iField].nType1 * 10)
     471             :             {
     472           0 :                 case AVC_FT_DATE:
     473             :                 case AVC_FT_FIXINT:
     474             :                 case AVC_FT_CHAR:
     475             :                 case AVC_FT_FIXNUM:
     476             :                 {
     477             :                     // XXX - I bet mloskot would like to see const_cast +
     478             :                     // static_cast :-)
     479           0 :                     const char *pszTmp =
     480           0 :                         (const char *)(pasFields[iField].pszStr);
     481           0 :                     CPLString osStrValue(pszTmp);
     482           0 :                     poRAT->SetValue(iRecord - 1, iField, osStrValue.Trim());
     483             :                 }
     484           0 :                 break;
     485             : 
     486           0 :                 case AVC_FT_BININT:
     487           0 :                     if (psTableDef->pasFieldDef[iField].nSize == 4)
     488           0 :                         poRAT->SetValue(iRecord - 1, iField,
     489           0 :                                         pasFields[iField].nInt32);
     490             :                     else
     491           0 :                         poRAT->SetValue(iRecord - 1, iField,
     492           0 :                                         pasFields[iField].nInt16);
     493           0 :                     break;
     494             : 
     495           0 :                 case AVC_FT_BINFLOAT:
     496           0 :                     if (psTableDef->pasFieldDef[iField].nSize == 4)
     497           0 :                         poRAT->SetValue(iRecord - 1, iField,
     498           0 :                                         pasFields[iField].fFloat);
     499             :                     else
     500           0 :                         poRAT->SetValue(iRecord - 1, iField,
     501           0 :                                         pasFields[iField].dDouble);
     502           0 :                     break;
     503             :             }
     504             :         }
     505             :     }
     506             : 
     507             :     /* -------------------------------------------------------------------- */
     508             :     /*      Cleanup                                                         */
     509             :     /* -------------------------------------------------------------------- */
     510             : 
     511           0 :     AVCBinReadClose(psFile);
     512             : 
     513             :     /* Workaround against #2447 and #3031, to avoid binding languages */
     514             :     /* not being able to open the dataset */
     515           0 :     CPLErrorReset();
     516             : }
     517             : 
     518             : /************************************************************************/
     519             : /*                                Open()                                */
     520             : /************************************************************************/
     521             : 
     522       35817 : GDALDataset *AIGDataset::Open(GDALOpenInfo *poOpenInfo)
     523             : 
     524             : {
     525             :     /* -------------------------------------------------------------------- */
     526             :     /*      If the pass name ends in .adf assume a file within the          */
     527             :     /*      coverage has been selected, and strip that off the coverage     */
     528             :     /*      name.                                                           */
     529             :     /* -------------------------------------------------------------------- */
     530       71631 :     CPLString osCoverName;
     531             : 
     532       35813 :     osCoverName = poOpenInfo->pszFilename;
     533       71217 :     if (osCoverName.size() > 4 &&
     534       35400 :         EQUAL(osCoverName.c_str() + osCoverName.size() - 4, ".adf"))
     535             :     {
     536           1 :         osCoverName = CPLGetDirname(poOpenInfo->pszFilename);
     537           1 :         if (osCoverName == "")
     538           0 :             osCoverName = ".";
     539             :     }
     540             : 
     541             :     /* -------------------------------------------------------------------- */
     542             :     /*      Otherwise verify we were already given a directory.             */
     543             :     /* -------------------------------------------------------------------- */
     544       35812 :     else if (!poOpenInfo->bIsDirectory)
     545             :     {
     546       35401 :         return nullptr;
     547             :     }
     548             : 
     549             :     /* -------------------------------------------------------------------- */
     550             :     /*      Verify that a few of the "standard" files are available.        */
     551             :     /* -------------------------------------------------------------------- */
     552             :     VSIStatBufL sStatBuf;
     553         825 :     CPLString osTestName;
     554             : 
     555         413 :     osTestName.Printf("%s/hdr.adf", osCoverName.c_str());
     556         413 :     if (VSIStatL(osTestName, &sStatBuf) != 0)
     557             :     {
     558         407 :         osTestName.Printf("%s/HDR.ADF", osCoverName.c_str());
     559         407 :         if (VSIStatL(osTestName, &sStatBuf) != 0)
     560         404 :             return nullptr;
     561             :     }
     562             : 
     563             :     /* -------------------------------------------------------------------- */
     564             :     /*      Confirm we have at least one raster data file.  These can be    */
     565             :     /*      sparse so we don't require particular ones to exists but if     */
     566             :     /*      there are none this is likely not a grid.                       */
     567             :     /* -------------------------------------------------------------------- */
     568           9 :     char **papszFileList = VSIReadDir(osCoverName);
     569           9 :     bool bGotOne = false;
     570             : 
     571           9 :     if (papszFileList == nullptr)
     572             :     {
     573             :         /* Useful when reading from /vsicurl/ on servers that don't */
     574             :         /* return a file list */
     575             :         /* such as
     576             :          * /vsicurl/http://eros.usgs.gov/archive/nslrsda/GeoTowns/NLCD/89110458
     577             :          */
     578             :         do
     579             :         {
     580           0 :             osTestName.Printf("%s/W001001.ADF", osCoverName.c_str());
     581           0 :             if (VSIStatL(osTestName, &sStatBuf) == 0)
     582             :             {
     583           0 :                 bGotOne = true;
     584           0 :                 break;
     585             :             }
     586             : 
     587           0 :             osTestName.Printf("%s/w001001.adf", osCoverName.c_str());
     588           0 :             if (VSIStatL(osTestName, &sStatBuf) == 0)
     589             :             {
     590           0 :                 bGotOne = true;
     591           0 :                 break;
     592             :             }
     593             :         } while (false);
     594             :     }
     595             : 
     596          44 :     for (int iFile = 0; papszFileList != nullptr &&
     597          44 :                         papszFileList[iFile] != nullptr && !bGotOne;
     598             :          iFile++)
     599             :     {
     600          35 :         if (strlen(papszFileList[iFile]) != 11)
     601          26 :             continue;
     602             : 
     603             :         // looking for something like w001001.adf or z001013.adf
     604           9 :         if (papszFileList[iFile][0] != 'w' && papszFileList[iFile][0] != 'W' &&
     605           0 :             papszFileList[iFile][0] != 'z' && papszFileList[iFile][0] != 'Z')
     606           0 :             continue;
     607             : 
     608           9 :         if (!STARTS_WITH(papszFileList[iFile] + 1, "0010"))
     609           0 :             continue;
     610             : 
     611           9 :         if (!EQUAL(papszFileList[iFile] + 7, ".adf"))
     612           0 :             continue;
     613             : 
     614           9 :         bGotOne = true;
     615             :     }
     616           9 :     CSLDestroy(papszFileList);
     617             : 
     618           9 :     if (!bGotOne)
     619           0 :         return nullptr;
     620             : 
     621             :     /* -------------------------------------------------------------------- */
     622             :     /*      Open the file.                                                  */
     623             :     /* -------------------------------------------------------------------- */
     624           9 :     AIGInfo_t *psInfo = AIGOpen(osCoverName.c_str(), "r");
     625             : 
     626           9 :     if (psInfo == nullptr)
     627             :     {
     628           0 :         CPLErrorReset();
     629           0 :         return nullptr;
     630             :     }
     631             : 
     632             :     /* -------------------------------------------------------------------- */
     633             :     /*      Confirm the requested access is supported.                      */
     634             :     /* -------------------------------------------------------------------- */
     635           9 :     if (poOpenInfo->eAccess == GA_Update)
     636             :     {
     637           0 :         AIGClose(psInfo);
     638           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     639             :                  "The AIG driver does not support update access to existing"
     640             :                  " datasets.\n");
     641           0 :         return nullptr;
     642             :     }
     643             :     /* -------------------------------------------------------------------- */
     644             :     /*      Create a corresponding GDALDataset.                             */
     645             :     /* -------------------------------------------------------------------- */
     646           9 :     AIGDataset *poDS = new AIGDataset();
     647             : 
     648           9 :     poDS->psInfo = psInfo;
     649             : 
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      Try to read a color table (.clr).  It seems it is legal to      */
     652             :     /*      have more than one so we just use the first one found.          */
     653             :     /* -------------------------------------------------------------------- */
     654           9 :     char **papszFiles = VSIReadDir(psInfo->pszCoverName);
     655          18 :     CPLString osClrFilename;
     656           9 :     CPLString osCleanPath = CPLCleanTrailingSlash(psInfo->pszCoverName);
     657             : 
     658             :     // first check for any .clr in coverage dir.
     659          43 :     for (int iFile = 0; papszFiles != nullptr && papszFiles[iFile] != nullptr;
     660             :          iFile++)
     661             :     {
     662          73 :         if (!EQUAL(CPLGetExtension(papszFiles[iFile]), "clr") &&
     663          34 :             !EQUAL(CPLGetExtension(papszFiles[iFile]), "CLR"))
     664          34 :             continue;
     665             : 
     666             :         osClrFilename =
     667           5 :             CPLFormFilename(psInfo->pszCoverName, papszFiles[iFile], nullptr);
     668           5 :         break;
     669             :     }
     670             : 
     671           9 :     CSLDestroy(papszFiles);
     672             : 
     673             :     // Look in parent if we don't find a .clr in the coverage dir.
     674           9 :     if (osClrFilename.empty())
     675             :     {
     676           8 :         CPLString osTestClrFilename;
     677             :         osTestClrFilename.Printf("%s/../%s.clr", psInfo->pszCoverName,
     678           4 :                                  CPLGetFilename(osCleanPath));
     679             : 
     680           4 :         if (VSIStatL(osTestClrFilename, &sStatBuf) != 0)
     681             :         {
     682             :             osTestClrFilename.Printf("%s/../%s.CLR", psInfo->pszCoverName,
     683           4 :                                      CPLGetFilename(osCleanPath));
     684             : 
     685           4 :             if (!VSIStatL(osTestClrFilename, &sStatBuf))
     686           2 :                 osClrFilename = std::move(osTestClrFilename);
     687             :         }
     688             :         else
     689           0 :             osClrFilename = std::move(osTestClrFilename);
     690             :     }
     691             : 
     692           9 :     if (!osClrFilename.empty())
     693           7 :         poDS->TranslateColorTable(osClrFilename);
     694             : 
     695             :     /* -------------------------------------------------------------------- */
     696             :     /*      Establish raster info.                                          */
     697             :     /* -------------------------------------------------------------------- */
     698           9 :     poDS->nRasterXSize = psInfo->nPixels;
     699           9 :     poDS->nRasterYSize = psInfo->nLines;
     700           9 :     poDS->nBands = 1;
     701             : 
     702             :     /* -------------------------------------------------------------------- */
     703             :     /*      Create band information objects.                                */
     704             :     /* -------------------------------------------------------------------- */
     705           9 :     poDS->SetBand(1, new AIGRasterBand(poDS, 1));
     706             : 
     707             :     /* -------------------------------------------------------------------- */
     708             :     /*      Try to read projection file.                                    */
     709             :     /* -------------------------------------------------------------------- */
     710             :     const char *pszPrjFilename =
     711           9 :         CPLFormCIFilename(psInfo->pszCoverName, "prj", "adf");
     712           9 :     if (VSIStatL(pszPrjFilename, &sStatBuf) == 0)
     713             :     {
     714          18 :         OGRSpatialReference oSRS;
     715           9 :         oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     716             : 
     717           9 :         poDS->papszPrj = CSLLoad(pszPrjFilename);
     718             : 
     719           9 :         if (oSRS.importFromESRI(poDS->papszPrj) == OGRERR_NONE)
     720             :         {
     721             :             // If geographic values are in seconds, we must transform.
     722             :             // Is there a code for minutes too?
     723          10 :             if (oSRS.IsGeographic() &&
     724          10 :                 EQUAL(OSR_GDS(poDS->papszPrj, "Units", ""), "DS"))
     725             :             {
     726           0 :                 psInfo->dfLLX /= 3600.0;
     727           0 :                 psInfo->dfURY /= 3600.0;
     728           0 :                 psInfo->dfCellSizeX /= 3600.0;
     729           0 :                 psInfo->dfCellSizeY /= 3600.0;
     730             :             }
     731             : 
     732           9 :             poDS->m_oSRS = std::move(oSRS);
     733             :         }
     734             :     }
     735             : 
     736             :     /* -------------------------------------------------------------------- */
     737             :     /*      Initialize any PAM information.                                 */
     738             :     /* -------------------------------------------------------------------- */
     739           9 :     poDS->SetDescription(psInfo->pszCoverName);
     740           9 :     poDS->TryLoadXML();
     741             : 
     742             :     /* -------------------------------------------------------------------- */
     743             :     /*      Open overviews.                                                 */
     744             :     /* -------------------------------------------------------------------- */
     745           9 :     poDS->oOvManager.Initialize(poDS, psInfo->pszCoverName);
     746             : 
     747           9 :     return poDS;
     748             : }
     749             : 
     750             : /************************************************************************/
     751             : /*                          GetGeoTransform()                           */
     752             : /************************************************************************/
     753             : 
     754           1 : CPLErr AIGDataset::GetGeoTransform(double *padfTransform)
     755             : 
     756             : {
     757           1 :     padfTransform[0] = psInfo->dfLLX;
     758           1 :     padfTransform[1] = psInfo->dfCellSizeX;
     759           1 :     padfTransform[2] = 0;
     760             : 
     761           1 :     padfTransform[3] = psInfo->dfURY;
     762           1 :     padfTransform[4] = 0;
     763           1 :     padfTransform[5] = -psInfo->dfCellSizeY;
     764             : 
     765           1 :     return CE_None;
     766             : }
     767             : 
     768             : /************************************************************************/
     769             : /*                          GetSpatialRef()                             */
     770             : /************************************************************************/
     771             : 
     772           1 : const OGRSpatialReference *AIGDataset::GetSpatialRef() const
     773             : 
     774             : {
     775           1 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     776             : }
     777             : 
     778             : /************************************************************************/
     779             : /*                        TranslateColorTable()                         */
     780             : /************************************************************************/
     781             : 
     782           7 : void AIGDataset::TranslateColorTable(const char *pszClrFilename)
     783             : 
     784             : {
     785           7 :     char **papszClrLines = CSLLoad(pszClrFilename);
     786           7 :     if (papszClrLines == nullptr)
     787           0 :         return;
     788             : 
     789           7 :     poCT = new GDALColorTable();
     790             : 
     791        1813 :     for (int iLine = 0; papszClrLines[iLine] != nullptr; iLine++)
     792             :     {
     793        1806 :         char **papszTokens = CSLTokenizeString(papszClrLines[iLine]);
     794             : 
     795        1806 :         if (CSLCount(papszTokens) >= 4 && papszTokens[0][0] != '#')
     796             :         {
     797             :             int nIndex;
     798             :             GDALColorEntry sEntry;
     799             : 
     800        1792 :             nIndex = atoi(papszTokens[0]);
     801        1792 :             sEntry.c1 = (short)atoi(papszTokens[1]);
     802        1792 :             sEntry.c2 = (short)atoi(papszTokens[2]);
     803        1792 :             sEntry.c3 = (short)atoi(papszTokens[3]);
     804        1792 :             sEntry.c4 = 255;
     805             : 
     806        1792 :             if ((nIndex < 0 || nIndex > 33000) ||
     807        1792 :                 (sEntry.c1 < 0 || sEntry.c1 > 255) ||
     808        1792 :                 (sEntry.c2 < 0 || sEntry.c2 > 255) ||
     809        1792 :                 (sEntry.c3 < 0 || sEntry.c3 > 255))
     810             :             {
     811           0 :                 CSLDestroy(papszTokens);
     812           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     813             :                          "Color table entry appears to be corrupt, skipping "
     814             :                          "the rest. ");
     815           0 :                 break;
     816             :             }
     817             : 
     818        1792 :             poCT->SetColorEntry(nIndex, &sEntry);
     819             :         }
     820             : 
     821        1806 :         CSLDestroy(papszTokens);
     822             :     }
     823             : 
     824           7 :     CSLDestroy(papszClrLines);
     825             : }
     826             : 
     827             : /************************************************************************/
     828             : /*                              OSR_GDS()                               */
     829             : /************************************************************************/
     830             : 
     831           1 : static CPLString OSR_GDS(char **papszNV, const char *pszField,
     832             :                          const char *pszDefaultValue)
     833             : 
     834             : {
     835           1 :     if (papszNV == nullptr || papszNV[0] == nullptr)
     836           0 :         return pszDefaultValue;
     837             : 
     838           1 :     int iLine = 0;
     839           4 :     for (; papszNV[iLine] != nullptr &&
     840           4 :            !EQUALN(papszNV[iLine], pszField, strlen(pszField));
     841             :          iLine++)
     842             :     {
     843             :     }
     844             : 
     845           1 :     if (papszNV[iLine] == nullptr)
     846           0 :         return pszDefaultValue;
     847             :     else
     848             :     {
     849           2 :         CPLString osResult;
     850           1 :         char **papszTokens = CSLTokenizeString(papszNV[iLine]);
     851             : 
     852           1 :         if (CSLCount(papszTokens) > 1)
     853           1 :             osResult = papszTokens[1];
     854             :         else
     855           0 :             osResult = pszDefaultValue;
     856             : 
     857           1 :         CSLDestroy(papszTokens);
     858           1 :         return osResult;
     859             :     }
     860             : }
     861             : 
     862             : /************************************************************************/
     863             : /*                             AIGRename()                              */
     864             : /*                                                                      */
     865             : /*      Custom renamer for AIG dataset.                                 */
     866             : /************************************************************************/
     867             : 
     868           0 : static CPLErr AIGRename(const char *pszNewName, const char *pszOldName)
     869             : 
     870             : {
     871             :     /* -------------------------------------------------------------------- */
     872             :     /*      Make sure we are talking about paths to the coverage            */
     873             :     /*      directory.                                                      */
     874             :     /* -------------------------------------------------------------------- */
     875           0 :     CPLString osOldPath, osNewPath;
     876             : 
     877           0 :     if (strlen(CPLGetExtension(pszNewName)) > 0)
     878           0 :         osNewPath = CPLGetPath(pszNewName);
     879             :     else
     880           0 :         osNewPath = pszNewName;
     881             : 
     882           0 :     if (strlen(CPLGetExtension(pszOldName)) > 0)
     883           0 :         osOldPath = CPLGetPath(pszOldName);
     884             :     else
     885           0 :         osOldPath = pszOldName;
     886             : 
     887             :     /* -------------------------------------------------------------------- */
     888             :     /*      Get file list.                                                  */
     889             :     /* -------------------------------------------------------------------- */
     890             : 
     891           0 :     GDALDatasetH hDS = GDALOpen(osOldPath, GA_ReadOnly);
     892           0 :     if (hDS == nullptr)
     893           0 :         return CE_Failure;
     894             : 
     895           0 :     char **papszFileList = GDALGetFileList(hDS);
     896           0 :     GDALClose(hDS);
     897             : 
     898           0 :     if (papszFileList == nullptr)
     899           0 :         return CE_Failure;
     900             : 
     901             :     /* -------------------------------------------------------------------- */
     902             :     /*      Work out the corresponding new names.                           */
     903             :     /* -------------------------------------------------------------------- */
     904           0 :     char **papszNewFileList = nullptr;
     905             : 
     906           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
     907             :     {
     908           0 :         CPLString osNewFilename;
     909             : 
     910           0 :         if (!EQUALN(papszFileList[i], osOldPath, osOldPath.size()))
     911             :         {
     912           0 :             CPLAssert(false);
     913             :             return CE_Failure;
     914             :         }
     915             : 
     916           0 :         osNewFilename = osNewPath + (papszFileList[i] + osOldPath.size());
     917             : 
     918           0 :         papszNewFileList = CSLAddString(papszNewFileList, osNewFilename);
     919             :     }
     920             : 
     921             :     /* -------------------------------------------------------------------- */
     922             :     /*      Try renaming the directory.                                     */
     923             :     /* -------------------------------------------------------------------- */
     924           0 :     if (VSIRename(osNewPath, osOldPath) != 0)
     925             :     {
     926           0 :         if (VSIMkdir(osNewPath, 0777) != 0)
     927             :         {
     928           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     929             :                      "Unable to create directory %s:\n%s", osNewPath.c_str(),
     930           0 :                      VSIStrerror(errno));
     931           0 :             CSLDestroy(papszNewFileList);
     932           0 :             return CE_Failure;
     933             :         }
     934             :     }
     935             : 
     936             :     /* -------------------------------------------------------------------- */
     937             :     /*      Copy/rename any remaining files.                                */
     938             :     /* -------------------------------------------------------------------- */
     939             :     VSIStatBufL sStatBuf;
     940             : 
     941           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
     942             :     {
     943           0 :         if (VSIStatL(papszFileList[i], &sStatBuf) == 0 &&
     944           0 :             VSI_ISREG(sStatBuf.st_mode))
     945             :         {
     946           0 :             if (CPLMoveFile(papszNewFileList[i], papszFileList[i]) != 0)
     947             :             {
     948           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     949           0 :                          "Unable to move %s to %s:\n%s", papszFileList[i],
     950           0 :                          papszNewFileList[i], VSIStrerror(errno));
     951           0 :                 CSLDestroy(papszNewFileList);
     952           0 :                 return CE_Failure;
     953             :             }
     954             :         }
     955             :     }
     956             : 
     957           0 :     if (VSIStatL(osOldPath, &sStatBuf) == 0)
     958             :     {
     959           0 :         if (CPLUnlinkTree(osOldPath) != 0)
     960             :         {
     961           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     962             :                      "Unable to cleanup old path.");
     963             :         }
     964             :     }
     965             : 
     966           0 :     CSLDestroy(papszFileList);
     967           0 :     CSLDestroy(papszNewFileList);
     968           0 :     return CE_None;
     969             : }
     970             : 
     971             : /************************************************************************/
     972             : /*                             AIGDelete()                              */
     973             : /*                                                                      */
     974             : /*      Custom dataset deleter for AIG dataset.                         */
     975             : /************************************************************************/
     976             : 
     977           0 : static CPLErr AIGDelete(const char *pszDatasetname)
     978             : 
     979             : {
     980             :     /* -------------------------------------------------------------------- */
     981             :     /*      Get file list.                                                  */
     982             :     /* -------------------------------------------------------------------- */
     983           0 :     GDALDatasetH hDS = GDALOpen(pszDatasetname, GA_ReadOnly);
     984           0 :     if (hDS == nullptr)
     985           0 :         return CE_Failure;
     986             : 
     987           0 :     char **papszFileList = GDALGetFileList(hDS);
     988           0 :     GDALClose(hDS);
     989             : 
     990           0 :     if (papszFileList == nullptr)
     991           0 :         return CE_Failure;
     992             : 
     993             :     /* -------------------------------------------------------------------- */
     994             :     /*      Delete all regular files.                                       */
     995             :     /* -------------------------------------------------------------------- */
     996           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
     997             :     {
     998             :         VSIStatBufL sStatBuf;
     999           0 :         if (VSIStatL(papszFileList[i], &sStatBuf) == 0 &&
    1000           0 :             VSI_ISREG(sStatBuf.st_mode))
    1001             :         {
    1002           0 :             if (VSIUnlink(papszFileList[i]) != 0)
    1003             :             {
    1004           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1005           0 :                          "Unable to delete '%s':\n%s", papszFileList[i],
    1006           0 :                          VSIStrerror(errno));
    1007           0 :                 return CE_Failure;
    1008             :             }
    1009             :         }
    1010             :     }
    1011             : 
    1012             :     /* -------------------------------------------------------------------- */
    1013             :     /*      Delete directories.                                             */
    1014             :     /* -------------------------------------------------------------------- */
    1015           0 :     for (int i = 0; papszFileList[i] != nullptr; i++)
    1016             :     {
    1017             :         VSIStatBufL sStatBuf;
    1018           0 :         if (VSIStatL(papszFileList[i], &sStatBuf) == 0 &&
    1019           0 :             VSI_ISDIR(sStatBuf.st_mode))
    1020             :         {
    1021           0 :             if (CPLUnlinkTree(papszFileList[i]) != 0)
    1022           0 :                 return CE_Failure;
    1023             :         }
    1024             :     }
    1025             : 
    1026           0 :     return CE_None;
    1027             : }
    1028             : 
    1029             : /************************************************************************/
    1030             : /*                          GDALRegister_AIG()                          */
    1031             : /************************************************************************/
    1032             : 
    1033        1595 : void GDALRegister_AIGrid()
    1034             : 
    1035             : {
    1036        1595 :     if (GDALGetDriverByName("AIG") != nullptr)
    1037         302 :         return;
    1038             : 
    1039        1293 :     GDALDriver *poDriver = new GDALDriver();
    1040             : 
    1041        1293 :     poDriver->SetDescription("AIG");
    1042        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1043        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Arc/Info Binary Grid");
    1044        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/aig.html");
    1045        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1046             : 
    1047        1293 :     poDriver->pfnOpen = AIGDataset::Open;
    1048             : 
    1049        1293 :     poDriver->pfnRename = AIGRename;
    1050        1293 :     poDriver->pfnDelete = AIGDelete;
    1051             : 
    1052        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1053             : }

Generated by: LCOV version 1.14