LCOV - code coverage report
Current view: top level - frmts/ctg - ctgdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 171 202 84.7 %
Date: 2024-05-06 11:10:03 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CTG driver
       4             :  * Purpose:  GDALDataset driver for CTG dataset.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "gdal_frmts.h"
      30             : #include "gdal_pam.h"
      31             : #include "ogr_spatialref.h"
      32             : 
      33             : constexpr int HEADER_LINE_COUNT = 5;
      34             : 
      35             : typedef struct
      36             : {
      37             :     int nCode;
      38             :     const char *pszDesc;
      39             : } LULCDescStruct;
      40             : 
      41             : static const LULCDescStruct asLULCDesc[] = {
      42             :     {1, "Urban or Built-Up Land"},
      43             :     {2, "Agricultural Land"},
      44             :     {3, "Rangeland"},
      45             :     {4, "Forest Land"},
      46             :     {5, "Water"},
      47             :     {6, "Wetland"},
      48             :     {7, "Barren Land"},
      49             :     {8, "Tundra"},
      50             :     {9, "Perennial Snow and Ice"},
      51             :     {11, "Residential"},
      52             :     {12, "Commercial Services"},
      53             :     {13, "Industrial"},
      54             :     {14, "Transportation, Communications"},
      55             :     {15, "Industrial and Commercial"},
      56             :     {16, "Mixed Urban or Built-Up Land"},
      57             :     {17, "Other Urban or Built-Up Land"},
      58             :     {21, "Cropland and Pasture"},
      59             :     {22, "Orchards, Groves, Vineyards, Nurseries"},
      60             :     {23, "Confined Feeding Operations"},
      61             :     {24, "Other Agricultural Land"},
      62             :     {31, "Herbaceous Rangeland"},
      63             :     {32, "Shrub and Brush Rangeland"},
      64             :     {33, "Mixed Rangeland"},
      65             :     {41, "Deciduous Forest Land"},
      66             :     {42, "Evergreen Forest Land"},
      67             :     {43, "Mixed Forest Land"},
      68             :     {51, "Streams and Canals"},
      69             :     {52, "Lakes"},
      70             :     {53, "Reservoirs"},
      71             :     {54, "Bays and Estuaries"},
      72             :     {61, "Forested Wetlands"},
      73             :     {62, "Nonforested Wetlands"},
      74             :     {71, "Dry Salt Flats"},
      75             :     {72, "Beaches"},
      76             :     {73, "Sandy Areas Other than Beaches"},
      77             :     {74, "Bare Exposed Rock"},
      78             :     {75, "Strip Mines, Quarries, and Gravel Pits"},
      79             :     {76, "Transitional Areas"},
      80             :     {77, "Mixed Barren Land"},
      81             :     {81, "Shrub and Brush Tundra"},
      82             :     {82, "Herbaceous Tundra"},
      83             :     {83, "Bare Ground"},
      84             :     {84, "Wet Tundra"},
      85             :     {85, "Mixed Tundra"},
      86             :     {91, "Perennial Snowfields"},
      87             :     {92, "Glaciers"}};
      88             : 
      89             : static const char *const apszBandDescription[] = {
      90             :     "Land Use and Land Cover",
      91             :     "Political units",
      92             :     "Census county subdivisions and SMSA tracts",
      93             :     "Hydrologic units",
      94             :     "Federal land ownership",
      95             :     "State land ownership"};
      96             : 
      97             : /************************************************************************/
      98             : /* ==================================================================== */
      99             : /*                              CTGDataset                              */
     100             : /* ==================================================================== */
     101             : /************************************************************************/
     102             : 
     103             : class CTGRasterBand;
     104             : 
     105             : class CTGDataset final : public GDALPamDataset
     106             : {
     107             :     friend class CTGRasterBand;
     108             : 
     109             :     VSILFILE *fp;
     110             : 
     111             :     int nNWEasting, nNWNorthing, nCellSize, nUTMZone;
     112             :     OGRSpatialReference m_oSRS{};
     113             : 
     114             :     int bHasReadImagery;
     115             :     GByte *pabyImage;
     116             : 
     117             :     int ReadImagery();
     118             : 
     119             :     static const char *ExtractField(char *szOutput, const char *pszBuffer,
     120             :                                     int nOffset, int nLength);
     121             : 
     122             :   public:
     123             :     CTGDataset();
     124             :     ~CTGDataset() override;
     125             : 
     126             :     CPLErr GetGeoTransform(double *) override;
     127             : 
     128           1 :     const OGRSpatialReference *GetSpatialRef() const override
     129             :     {
     130           1 :         return &m_oSRS;
     131             :     }
     132             : 
     133             :     static GDALDataset *Open(GDALOpenInfo *);
     134             :     static int Identify(GDALOpenInfo *);
     135             : };
     136             : 
     137             : /************************************************************************/
     138             : /* ==================================================================== */
     139             : /*                            CTGRasterBand                             */
     140             : /* ==================================================================== */
     141             : /************************************************************************/
     142             : 
     143             : class CTGRasterBand final : public GDALPamRasterBand
     144             : {
     145             :     friend class CTGDataset;
     146             : 
     147             :     char **papszCategories;
     148             : 
     149             :   public:
     150             :     CTGRasterBand(CTGDataset *, int);
     151             :     ~CTGRasterBand() override;
     152             : 
     153             :     CPLErr IReadBlock(int, int, void *) override;
     154             :     double GetNoDataValue(int *pbSuccess = nullptr) override;
     155             :     char **GetCategoryNames() override;
     156             : };
     157             : 
     158             : /************************************************************************/
     159             : /*                           CTGRasterBand()                            */
     160             : /************************************************************************/
     161             : 
     162          18 : CTGRasterBand::CTGRasterBand(CTGDataset *poDSIn, int nBandIn)
     163          18 :     : papszCategories(nullptr)
     164             : {
     165          18 :     poDS = poDSIn;
     166          18 :     nBand = nBandIn;
     167             : 
     168          18 :     eDataType = GDT_Int32;
     169             : 
     170          18 :     nBlockXSize = poDS->GetRasterXSize();
     171          18 :     nBlockYSize = poDS->GetRasterYSize();
     172          18 : }
     173             : 
     174             : /************************************************************************/
     175             : /*                          ~CTGRasterBand()                            */
     176             : /************************************************************************/
     177             : 
     178          36 : CTGRasterBand::~CTGRasterBand()
     179             : 
     180             : {
     181          18 :     CSLDestroy(papszCategories);
     182          36 : }
     183             : 
     184             : /************************************************************************/
     185             : /*                             IReadBlock()                             */
     186             : /************************************************************************/
     187             : 
     188           1 : CPLErr CTGRasterBand::IReadBlock(int /* nBlockXOff */, int /* nBlockYOff */,
     189             :                                  void *pImage)
     190             : {
     191           1 :     CTGDataset *poGDS = (CTGDataset *)poDS;
     192             : 
     193           1 :     poGDS->ReadImagery();
     194           1 :     memcpy(pImage,
     195           1 :            poGDS->pabyImage +
     196           1 :                sizeof(int) * (nBand - 1) * nBlockXSize * nBlockYSize,
     197           1 :            sizeof(int) * nBlockXSize * nBlockYSize);
     198             : 
     199           1 :     return CE_None;
     200             : }
     201             : 
     202             : /************************************************************************/
     203             : /*                           GetNoDataValue()                           */
     204             : /************************************************************************/
     205             : 
     206           1 : double CTGRasterBand::GetNoDataValue(int *pbSuccess)
     207             : {
     208           1 :     if (pbSuccess)
     209           1 :         *pbSuccess = TRUE;
     210             : 
     211           1 :     return 0.0;
     212             : }
     213             : 
     214             : /************************************************************************/
     215             : /*                          GetCategoryNames()                          */
     216             : /************************************************************************/
     217             : 
     218           2 : char **CTGRasterBand::GetCategoryNames()
     219             : {
     220           2 :     if (nBand != 1)
     221           1 :         return nullptr;
     222             : 
     223           1 :     if (papszCategories != nullptr)
     224           0 :         return papszCategories;
     225             : 
     226           1 :     int nasLULCDescSize = (int)(sizeof(asLULCDesc) / sizeof(asLULCDesc[0]));
     227           1 :     int nCategoriesSize = asLULCDesc[nasLULCDescSize - 1].nCode;
     228           1 :     papszCategories = (char **)CPLCalloc(nCategoriesSize + 2, sizeof(char *));
     229          47 :     for (int i = 0; i < nasLULCDescSize; i++)
     230             :     {
     231          46 :         papszCategories[asLULCDesc[i].nCode] = CPLStrdup(asLULCDesc[i].pszDesc);
     232             :     }
     233          93 :     for (int i = 0; i < nCategoriesSize; i++)
     234             :     {
     235          92 :         if (papszCategories[i] == nullptr)
     236          47 :             papszCategories[i] = CPLStrdup("");
     237             :     }
     238           1 :     papszCategories[nCategoriesSize + 1] = nullptr;
     239             : 
     240           1 :     return papszCategories;
     241             : }
     242             : 
     243             : /************************************************************************/
     244             : /*                            ~CTGDataset()                            */
     245             : /************************************************************************/
     246             : 
     247           3 : CTGDataset::CTGDataset()
     248             :     : fp(nullptr), nNWEasting(0), nNWNorthing(0), nCellSize(0), nUTMZone(0),
     249           3 :       bHasReadImagery(FALSE), pabyImage(nullptr)
     250             : {
     251           3 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     252           3 : }
     253             : 
     254             : /************************************************************************/
     255             : /*                            ~CTGDataset()                            */
     256             : /************************************************************************/
     257             : 
     258           6 : CTGDataset::~CTGDataset()
     259             : 
     260             : {
     261           3 :     CPLFree(pabyImage);
     262           3 :     if (fp != nullptr)
     263           3 :         VSIFCloseL(fp);
     264           6 : }
     265             : 
     266             : /************************************************************************/
     267             : /*                              ExtractField()                          */
     268             : /************************************************************************/
     269             : 
     270          69 : const char *CTGDataset::ExtractField(char *szField, const char *pszBuffer,
     271             :                                      int nOffset, int nLength)
     272             : {
     273          69 :     CPLAssert(nLength <= 10);
     274          69 :     memcpy(szField, pszBuffer + nOffset, nLength);
     275          69 :     szField[nLength] = 0;
     276          69 :     return szField;
     277             : }
     278             : 
     279             : /************************************************************************/
     280             : /*                            ReadImagery()                             */
     281             : /************************************************************************/
     282             : 
     283           1 : int CTGDataset::ReadImagery()
     284             : {
     285           1 :     if (bHasReadImagery)
     286           0 :         return TRUE;
     287             : 
     288           1 :     bHasReadImagery = TRUE;
     289             : 
     290             :     char szLine[81];
     291             :     char szField[11];
     292           1 :     szLine[80] = 0;
     293           1 :     int nLine = HEADER_LINE_COUNT;
     294           1 :     VSIFSeekL(fp, nLine * 80, SEEK_SET);
     295           1 :     const int nCells = nRasterXSize * nRasterYSize;
     296           2 :     while (VSIFReadL(szLine, 1, 80, fp) == 80)
     297             :     {
     298           1 :         const int nZone = atoi(ExtractField(szField, szLine, 0, 3));
     299           1 :         if (nZone != nUTMZone)
     300             :         {
     301           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     302             :                      "Read error at line %d, %s. Did not expected UTM zone %d",
     303             :                      nLine, szLine, nZone);
     304           0 :             return FALSE;
     305             :         }
     306             :         const int nX =
     307           1 :             atoi(ExtractField(szField, szLine, 3, 8)) - nCellSize / 2;
     308             :         const int nY =
     309           1 :             atoi(ExtractField(szField, szLine, 11, 8)) + nCellSize / 2;
     310           1 :         const GIntBig nDiffX = static_cast<GIntBig>(nX) - nNWEasting;
     311           1 :         const GIntBig nDiffY = static_cast<GIntBig>(nNWNorthing) - nY;
     312           1 :         if (nDiffX < 0 || (nDiffX % nCellSize) != 0 || nDiffY < 0 ||
     313           1 :             (nDiffY % nCellSize) != 0)
     314             :         {
     315           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     316             :                      "Read error at line %d, %s. Unexpected cell coordinates",
     317             :                      nLine, szLine);
     318           0 :             return FALSE;
     319             :         }
     320           1 :         const GIntBig nCellX = nDiffX / nCellSize;
     321           1 :         const GIntBig nCellY = nDiffY / nCellSize;
     322           1 :         if (nCellX >= nRasterXSize || nCellY >= nRasterYSize)
     323             :         {
     324           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     325             :                      "Read error at line %d, %s. Unexpected cell coordinates",
     326             :                      nLine, szLine);
     327           0 :             return FALSE;
     328             :         }
     329           7 :         for (int i = 0; i < 6; i++)
     330             :         {
     331           6 :             int nVal = atoi(ExtractField(szField, szLine, 20 + 10 * i, 10));
     332           6 :             if (nVal >= 2000000000)
     333           0 :                 nVal = 0;
     334             :             ((int *)
     335           6 :                  pabyImage)[i * nCells +
     336           6 :                             static_cast<int>(nCellY) * nRasterXSize + nCellX] =
     337             :                 nVal;
     338             :         }
     339             : 
     340           1 :         nLine++;
     341             :     }
     342             : 
     343           1 :     return TRUE;
     344             : }
     345             : 
     346             : /************************************************************************/
     347             : /*                             Identify()                               */
     348             : /************************************************************************/
     349             : 
     350       48006 : int CTGDataset::Identify(GDALOpenInfo *poOpenInfo)
     351             : {
     352       96010 :     CPLString osFilename;  // let in that scope
     353             : 
     354       48006 :     GDALOpenInfo *poOpenInfoToDelete = nullptr;
     355             :     /*  GZipped grid_cell.gz files are common, so automagically open them */
     356             :     /*  if the /vsigzip/ has not been explicitly passed */
     357       48006 :     const char *pszFilename = CPLGetFilename(poOpenInfo->pszFilename);
     358       48005 :     if ((EQUAL(pszFilename, "grid_cell.gz") ||
     359       48006 :          EQUAL(pszFilename, "grid_cell1.gz") ||
     360       48006 :          EQUAL(pszFilename, "grid_cell2.gz")) &&
     361           0 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "/vsigzip/"))
     362             :     {
     363           0 :         osFilename = "/vsigzip/";
     364           0 :         osFilename += poOpenInfo->pszFilename;
     365           0 :         poOpenInfo = poOpenInfoToDelete = new GDALOpenInfo(
     366           0 :             osFilename.c_str(), GA_ReadOnly, poOpenInfo->GetSiblingFiles());
     367             :     }
     368             : 
     369       48005 :     if (poOpenInfo->nHeaderBytes < HEADER_LINE_COUNT * 80)
     370             :     {
     371       45881 :         delete poOpenInfoToDelete;
     372       45880 :         return FALSE;
     373             :     }
     374             : 
     375             :     /* -------------------------------------------------------------------- */
     376             :     /*      Check that it looks roughly as a CTG dataset                    */
     377             :     /* -------------------------------------------------------------------- */
     378        2124 :     const char *pszData = (const char *)poOpenInfo->pabyHeader;
     379        4683 :     for (int i = 0; i < 4 * 80; i++)
     380             :     {
     381        4676 :         if (!((pszData[i] >= '0' && pszData[i] <= '9') || pszData[i] == ' ' ||
     382        2119 :               pszData[i] == '-'))
     383             :         {
     384        2117 :             delete poOpenInfoToDelete;
     385        2117 :             return FALSE;
     386             :         }
     387             :     }
     388             : 
     389             :     char szField[11];
     390           7 :     int nRows = atoi(ExtractField(szField, pszData, 0, 10));
     391           7 :     int nCols = atoi(ExtractField(szField, pszData, 20, 10));
     392           7 :     int nMinColIndex = atoi(ExtractField(szField, pszData + 80, 0, 5));
     393           7 :     int nMinRowIndex = atoi(ExtractField(szField, pszData + 80, 5, 5));
     394           7 :     int nMaxColIndex = atoi(ExtractField(szField, pszData + 80, 10, 5));
     395           7 :     int nMaxRowIndex = atoi(ExtractField(szField, pszData + 80, 15, 5));
     396             : 
     397           7 :     if (nRows <= 0 || nCols <= 0 || nMinColIndex != 1 || nMinRowIndex != 1 ||
     398           6 :         nMaxRowIndex != nRows || nMaxColIndex != nCols)
     399             :     {
     400           1 :         delete poOpenInfoToDelete;
     401           1 :         return FALSE;
     402             :     }
     403             : 
     404           6 :     delete poOpenInfoToDelete;
     405           6 :     return TRUE;
     406             : }
     407             : 
     408             : /************************************************************************/
     409             : /*                                Open()                                */
     410             : /************************************************************************/
     411             : 
     412           3 : GDALDataset *CTGDataset::Open(GDALOpenInfo *poOpenInfo)
     413             : 
     414             : {
     415           3 :     if (!Identify(poOpenInfo))
     416           0 :         return nullptr;
     417             : 
     418           6 :     CPLString osFilename(poOpenInfo->pszFilename);
     419             : 
     420             :     /*  GZipped grid_cell.gz files are common, so automagically open them */
     421             :     /*  if the /vsigzip/ has not been explicitly passed */
     422           3 :     const char *pszFilename = CPLGetFilename(poOpenInfo->pszFilename);
     423           3 :     if ((EQUAL(pszFilename, "grid_cell.gz") ||
     424           3 :          EQUAL(pszFilename, "grid_cell1.gz") ||
     425           3 :          EQUAL(pszFilename, "grid_cell2.gz")) &&
     426           0 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "/vsigzip/"))
     427             :     {
     428           0 :         osFilename = "/vsigzip/";
     429           0 :         osFilename += poOpenInfo->pszFilename;
     430             :     }
     431             : 
     432           3 :     if (poOpenInfo->eAccess == GA_Update)
     433             :     {
     434           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     435             :                  "The CTG driver does not support update access to existing"
     436             :                  " datasets.\n");
     437           0 :         return nullptr;
     438             :     }
     439             : 
     440             :     /* -------------------------------------------------------------------- */
     441             :     /*      Find dataset characteristics                                    */
     442             :     /* -------------------------------------------------------------------- */
     443           3 :     VSILFILE *fp = VSIFOpenL(osFilename.c_str(), "rb");
     444           3 :     if (fp == nullptr)
     445           0 :         return nullptr;
     446             : 
     447             :     char szHeader[HEADER_LINE_COUNT * 80 + 1];
     448           3 :     szHeader[HEADER_LINE_COUNT * 80] = 0;
     449           3 :     if (VSIFReadL(szHeader, 1, HEADER_LINE_COUNT * 80, fp) !=
     450             :         HEADER_LINE_COUNT * 80)
     451             :     {
     452           0 :         VSIFCloseL(fp);
     453           0 :         return nullptr;
     454             :     }
     455             : 
     456         216 :     for (int i = HEADER_LINE_COUNT * 80 - 1; i >= 0; i--)
     457             :     {
     458         216 :         if (szHeader[i] == ' ')
     459         213 :             szHeader[i] = 0;
     460             :         else
     461           3 :             break;
     462             :     }
     463             : 
     464             :     char szField[11];
     465           3 :     int nRows = atoi(ExtractField(szField, szHeader, 0, 10));
     466           3 :     int nCols = atoi(ExtractField(szField, szHeader, 20, 10));
     467             : 
     468             :     /* -------------------------------------------------------------------- */
     469             :     /*      Create a corresponding GDALDataset.                             */
     470             :     /* -------------------------------------------------------------------- */
     471           3 :     CTGDataset *poDS = new CTGDataset();
     472           3 :     poDS->fp = fp;
     473           3 :     fp = nullptr;
     474           3 :     poDS->nRasterXSize = nCols;
     475           3 :     poDS->nRasterYSize = nRows;
     476             : 
     477           3 :     poDS->SetMetadataItem("TITLE", szHeader + 4 * 80);
     478             : 
     479           3 :     poDS->nCellSize = atoi(ExtractField(szField, szHeader, 35, 5));
     480           3 :     if (poDS->nCellSize <= 0 || poDS->nCellSize >= 10000)
     481             :     {
     482           0 :         delete poDS;
     483           0 :         return nullptr;
     484             :     }
     485           3 :     poDS->nNWEasting = atoi(ExtractField(szField, szHeader + 3 * 80, 40, 10));
     486           3 :     poDS->nNWNorthing = atoi(ExtractField(szField, szHeader + 3 * 80, 50, 10));
     487           3 :     poDS->nUTMZone = atoi(ExtractField(szField, szHeader, 50, 5));
     488           3 :     if (poDS->nUTMZone <= 0 || poDS->nUTMZone > 60)
     489             :     {
     490           0 :         delete poDS;
     491           0 :         return nullptr;
     492             :     }
     493             : 
     494           3 :     poDS->m_oSRS.importFromEPSG(32600 + poDS->nUTMZone);
     495             : 
     496           3 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     497             :     {
     498           0 :         delete poDS;
     499           0 :         return nullptr;
     500             :     }
     501             : 
     502             :     /* -------------------------------------------------------------------- */
     503             :     /*      Read the imagery                                                */
     504             :     /* -------------------------------------------------------------------- */
     505             :     GByte *pabyImage =
     506           3 :         (GByte *)VSICalloc(static_cast<size_t>(nCols) * nRows, 6 * sizeof(int));
     507           3 :     if (pabyImage == nullptr)
     508             :     {
     509           0 :         delete poDS;
     510           0 :         return nullptr;
     511             :     }
     512           3 :     poDS->pabyImage = pabyImage;
     513             : 
     514             :     /* -------------------------------------------------------------------- */
     515             :     /*      Create band information objects.                                */
     516             :     /* -------------------------------------------------------------------- */
     517           3 :     poDS->nBands = 6;
     518          21 :     for (int i = 0; i < poDS->nBands; i++)
     519             :     {
     520          18 :         poDS->SetBand(i + 1, new CTGRasterBand(poDS, i + 1));
     521          18 :         poDS->GetRasterBand(i + 1)->SetDescription(apszBandDescription[i]);
     522             :     }
     523             : 
     524             :     /* -------------------------------------------------------------------- */
     525             :     /*      Initialize any PAM information.                                 */
     526             :     /* -------------------------------------------------------------------- */
     527           3 :     poDS->SetDescription(poOpenInfo->pszFilename);
     528           3 :     poDS->TryLoadXML();
     529             : 
     530             :     /* -------------------------------------------------------------------- */
     531             :     /*      Support overviews.                                              */
     532             :     /* -------------------------------------------------------------------- */
     533           3 :     poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
     534             : 
     535           3 :     return poDS;
     536             : }
     537             : 
     538             : /************************************************************************/
     539             : /*                          GetGeoTransform()                           */
     540             : /************************************************************************/
     541             : 
     542           1 : CPLErr CTGDataset::GetGeoTransform(double *padfTransform)
     543             : 
     544             : {
     545           1 :     padfTransform[0] = static_cast<double>(nNWEasting) - nCellSize / 2;
     546           1 :     padfTransform[1] = nCellSize;
     547           1 :     padfTransform[2] = 0;
     548           1 :     padfTransform[3] = static_cast<double>(nNWNorthing) + nCellSize / 2;
     549           1 :     padfTransform[4] = 0.;
     550           1 :     padfTransform[5] = -nCellSize;
     551             : 
     552           1 :     return CE_None;
     553             : }
     554             : 
     555             : /************************************************************************/
     556             : /*                         GDALRegister_CTG()                           */
     557             : /************************************************************************/
     558             : 
     559        1520 : void GDALRegister_CTG()
     560             : 
     561             : {
     562        1520 :     if (GDALGetDriverByName("CTG") != nullptr)
     563         301 :         return;
     564             : 
     565        1219 :     GDALDriver *poDriver = new GDALDriver();
     566             : 
     567        1219 :     poDriver->SetDescription("CTG");
     568        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     569        1219 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     570        1219 :                               "USGS LULC Composite Theme Grid");
     571        1219 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/ctg.html");
     572             : 
     573        1219 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     574             : 
     575        1219 :     poDriver->pfnOpen = CTGDataset::Open;
     576        1219 :     poDriver->pfnIdentify = CTGDataset::Identify;
     577             : 
     578        1219 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     579             : }

Generated by: LCOV version 1.14