LCOV - code coverage report
Current view: directory - frmts/raw - snodasdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 209 199 95.2 %
Date: 2012-12-26 Functions: 18 13 72.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: snodasdataset.cpp 21984 2011-03-19 17:22:58Z rouault $
       3                 :  *
       4                 :  * Project:  SNODAS driver
       5                 :  * Purpose:  Implementation of SNODASDataset
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2011, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "rawdataset.h"
      31                 : #include "ogr_srs_api.h"
      32                 : #include "cpl_string.h"
      33                 : 
      34                 : CPL_CVSID("$Id: snodasdataset.cpp 21984 2011-03-19 17:22:58Z rouault $");
      35                 : 
      36                 : // g++ -g -Wall -fPIC frmts/raw/snodasdataset.cpp -shared -o gdal_SNODAS.so -Iport -Igcore -Ifrmts/raw -Iogr -L. -lgdal
      37                 : 
      38                 : CPL_C_START
      39                 : void    GDALRegister_SNODAS(void);
      40                 : CPL_C_END
      41                 : 
      42                 : /************************************************************************/
      43                 : /* ==================================================================== */
      44                 : /*                            SNODASDataset                             */
      45                 : /* ==================================================================== */
      46                 : /************************************************************************/
      47                 : 
      48                 : class SNODASRasterBand;
      49                 : 
      50                 : class SNODASDataset : public RawDataset
      51                 : {
      52                 :     CPLString   osDataFilename;
      53                 :     int         bGotTransform;
      54                 :     double      adfGeoTransform[6];
      55                 :     int         bHasNoData;
      56                 :     double      dfNoData;
      57                 :     int         bHasMin;
      58                 :     double      dfMin;
      59                 :     int         bHasMax;
      60                 :     double      dfMax;
      61                 : 
      62                 :     friend class SNODASRasterBand;
      63                 : 
      64                 :   public:
      65                 :                     SNODASDataset();
      66                 :                     ~SNODASDataset();
      67                 : 
      68                 :     virtual CPLErr GetGeoTransform( double * padfTransform );
      69                 :     virtual const char *GetProjectionRef(void);
      70                 : 
      71                 :     virtual char **GetFileList();
      72                 : 
      73                 :     static GDALDataset *Open( GDALOpenInfo * );
      74                 :     static int Identify( GDALOpenInfo * );
      75                 : };
      76                 : 
      77                 : 
      78                 : /************************************************************************/
      79                 : /* ==================================================================== */
      80                 : /*                            SNODASRasterBand                          */
      81                 : /* ==================================================================== */
      82                 : /************************************************************************/
      83                 : 
      84                 : class SNODASRasterBand : public RawRasterBand
      85               2 : {
      86                 :     public:
      87                 :             SNODASRasterBand(VSILFILE* fpRaw, int nXSize, int nYSize);
      88                 : 
      89                 :         virtual double GetNoDataValue( int *pbSuccess = NULL );
      90                 :         virtual double GetMinimum( int *pbSuccess = NULL );
      91                 :         virtual double GetMaximum(int *pbSuccess = NULL );
      92                 : };
      93                 : 
      94                 : 
      95                 : /************************************************************************/
      96                 : /*                         SNODASRasterBand()                           */
      97                 : /************************************************************************/
      98                 : 
      99               2 : SNODASRasterBand::SNODASRasterBand(VSILFILE* fpRaw,
     100                 :                                    int nXSize, int nYSize) :
     101                 :     RawRasterBand( fpRaw, 0, 2,
     102                 :                    nXSize * 2, GDT_Int16,
     103               2 :                    !CPL_IS_LSB, nXSize, nYSize, TRUE, TRUE)
     104                 : {
     105               2 : }
     106                 : 
     107                 : /************************************************************************/
     108                 : /*                          GetNoDataValue()                            */
     109                 : /************************************************************************/
     110                 : 
     111               1 : double SNODASRasterBand::GetNoDataValue( int *pbSuccess )
     112                 : {
     113               1 :     SNODASDataset* poGDS = (SNODASDataset*) poDS;
     114               1 :     if (pbSuccess)
     115               1 :         *pbSuccess = poGDS->bHasNoData;
     116               1 :     if (poGDS->bHasNoData)
     117               1 :         return poGDS->dfNoData;
     118                 :     else
     119               0 :         return RawRasterBand::GetNoDataValue(pbSuccess);
     120                 : }
     121                 : 
     122                 : /************************************************************************/
     123                 : /*                            GetMinimum()                              */
     124                 : /************************************************************************/
     125                 : 
     126               1 : double SNODASRasterBand::GetMinimum( int *pbSuccess )
     127                 : {
     128               1 :     SNODASDataset* poGDS = (SNODASDataset*) poDS;
     129               1 :     if (pbSuccess)
     130               1 :         *pbSuccess = poGDS->bHasMin;
     131               1 :     if (poGDS->bHasMin)
     132               1 :         return poGDS->dfMin;
     133                 :     else
     134               0 :         return RawRasterBand::GetMinimum(pbSuccess);
     135                 : }
     136                 : 
     137                 : /************************************************************************/
     138                 : /*                            GetMaximum()                             */
     139                 : /************************************************************************/
     140                 : 
     141               1 : double SNODASRasterBand::GetMaximum( int *pbSuccess )
     142                 : {
     143               1 :     SNODASDataset* poGDS = (SNODASDataset*) poDS;
     144               1 :     if (pbSuccess)
     145               1 :         *pbSuccess = poGDS->bHasMax;
     146               1 :     if (poGDS->bHasMax)
     147               1 :         return poGDS->dfMax;
     148                 :     else
     149               0 :         return RawRasterBand::GetMaximum(pbSuccess);
     150                 : }
     151                 : 
     152                 : /************************************************************************/
     153                 : /* ==================================================================== */
     154                 : /*                            SNODASDataset                             */
     155                 : /* ==================================================================== */
     156                 : /************************************************************************/
     157                 : 
     158                 : /************************************************************************/
     159                 : /*                           SNODASDataset()                            */
     160                 : /************************************************************************/
     161                 : 
     162               2 : SNODASDataset::SNODASDataset()
     163                 : {
     164               2 :     bGotTransform = FALSE;
     165               2 :     adfGeoTransform[0] = 0.0;
     166               2 :     adfGeoTransform[1] = 1.0;
     167               2 :     adfGeoTransform[2] = 0.0;
     168               2 :     adfGeoTransform[3] = 0.0;
     169               2 :     adfGeoTransform[4] = 0.0;
     170               2 :     adfGeoTransform[5] = 1.0;
     171               2 :     bHasNoData = FALSE;
     172               2 :     dfNoData = 0.0;
     173               2 :     bHasMin = FALSE;
     174               2 :     dfMin = 0.0;
     175               2 :     bHasMax = FALSE;
     176               2 :     dfMax = 0.0;
     177               2 : }
     178                 : 
     179                 : /************************************************************************/
     180                 : /*                           ~SNODASDataset()                           */
     181                 : /************************************************************************/
     182                 : 
     183               2 : SNODASDataset::~SNODASDataset()
     184                 : 
     185                 : {
     186               2 :     FlushCache();
     187               2 : }
     188                 : 
     189                 : /************************************************************************/
     190                 : /*                          GetProjectionRef()                          */
     191                 : /************************************************************************/
     192                 : 
     193               1 : const char *SNODASDataset::GetProjectionRef()
     194                 : 
     195                 : {
     196               1 :     return SRS_WKT_WGS84;
     197                 : }
     198                 : 
     199                 : /************************************************************************/
     200                 : /*                          GetGeoTransform()                           */
     201                 : /************************************************************************/
     202                 : 
     203               1 : CPLErr SNODASDataset::GetGeoTransform( double * padfTransform )
     204                 : 
     205                 : {
     206               1 :     if( bGotTransform )
     207                 :     {
     208               1 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
     209               1 :         return CE_None;
     210                 :     }
     211                 :     else
     212                 :     {
     213               0 :         return GDALPamDataset::GetGeoTransform( padfTransform );
     214                 :     }
     215                 : }
     216                 : 
     217                 : 
     218                 : /************************************************************************/
     219                 : /*                            GetFileList()                             */
     220                 : /************************************************************************/
     221                 : 
     222               1 : char **SNODASDataset::GetFileList()
     223                 : 
     224                 : {
     225               1 :     char **papszFileList = GDALPamDataset::GetFileList();
     226                 : 
     227               1 :     papszFileList = CSLAddString(papszFileList, osDataFilename);
     228                 : 
     229               1 :     return papszFileList;
     230                 : }
     231                 : 
     232                 : /************************************************************************/
     233                 : /*                            Identify()                                */
     234                 : /************************************************************************/
     235                 : 
     236           11922 : int SNODASDataset::Identify( GDALOpenInfo * poOpenInfo )
     237                 : {
     238           11922 :     if (poOpenInfo->nHeaderBytes == 0)
     239           11278 :         return FALSE;
     240                 : 
     241             644 :     return EQUALN((const char*)poOpenInfo->pabyHeader,
     242                 :                   "Format version: NOHRSC GIS/RS raster file v1.1",
     243                 :                   strlen("Format version: NOHRSC GIS/RS raster file v1.1"));
     244                 : }
     245                 : 
     246                 : /************************************************************************/
     247                 : /*                                Open()                                */
     248                 : /************************************************************************/
     249                 : 
     250            1829 : GDALDataset *SNODASDataset::Open( GDALOpenInfo * poOpenInfo )
     251                 : 
     252                 : {
     253            1829 :     if( !Identify(poOpenInfo) )
     254            1827 :         return NULL;
     255                 : 
     256                 :     VSILFILE    *fp;
     257                 : 
     258               2 :     fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
     259                 : 
     260               2 :     if( fp == NULL )
     261                 :     {
     262               0 :         return NULL;
     263                 :     }
     264                 : 
     265                 :     const char *    pszLine;
     266               2 :     int             nRows = -1, nCols = -1;
     267               2 :     CPLString       osDataFilename;
     268               2 :     int             bIsInteger = FALSE, bIs2Bytes = FALSE;
     269               2 :     double          dfNoData = 0;
     270               2 :     int             bHasNoData = FALSE;
     271               2 :     double          dfMin = 0;
     272               2 :     int             bHasMin = FALSE;
     273               2 :     double          dfMax = 0;
     274               2 :     int             bHasMax = FALSE;
     275               2 :     double          dfMinX = 0.0, dfMinY = 0.0, dfMaxX = 0.0, dfMaxY = 0.0;
     276               2 :     int             bHasMinX = FALSE, bHasMinY = FALSE, bHasMaxX = FALSE, bHasMaxY = FALSE;
     277               2 :     int             bNotProjected = FALSE, bIsWGS84 = FALSE;
     278               2 :     CPLString       osDescription, osDataUnits;
     279               2 :     int             nStartYear = -1, nStartMonth = -1, nStartDay = -1,
     280               2 :                     nStartHour = -1, nStartMinute = -1, nStartSecond = -1;
     281               2 :     int             nStopYear = -1, nStopMonth = -1, nStopDay = -1,
     282               2 :                     nStopHour = -1, nStopMinute = -1, nStopSecond = -1;
     283                 : 
     284             218 :     while( (pszLine = CPLReadLine2L( fp, 256, NULL )) != NULL )
     285                 :     {
     286             214 :         char** papszTokens = CSLTokenizeStringComplex( pszLine, ":", TRUE, FALSE );
     287             214 :         if( CSLCount( papszTokens ) != 2 )
     288                 :         {
     289               2 :             CSLDestroy( papszTokens );
     290               2 :             continue;
     291                 :         }
     292             212 :         if( papszTokens[1][0] == ' ' )
     293             212 :             memmove(papszTokens[1], papszTokens[1] + 1, strlen(papszTokens[1] + 1) + 1);
     294                 : 
     295             212 :         if( EQUAL(papszTokens[0],"Data file pathname") )
     296                 :         {
     297               2 :             osDataFilename = papszTokens[1];
     298                 :         }
     299             210 :         else if( EQUAL(papszTokens[0],"Description") )
     300                 :         {
     301               2 :             osDescription = papszTokens[1];
     302                 :         }
     303             208 :         else if( EQUAL(papszTokens[0],"Data units") )
     304                 :         {
     305               2 :             osDataUnits= papszTokens[1];
     306                 :         }
     307                 : 
     308             206 :         else if( EQUAL(papszTokens[0],"Start year") )
     309               2 :             nStartYear = atoi(papszTokens[1]);
     310             204 :         else if( EQUAL(papszTokens[0],"Start month") )
     311               2 :             nStartMonth = atoi(papszTokens[1]);
     312             202 :         else if( EQUAL(papszTokens[0],"Start day") )
     313               2 :             nStartDay = atoi(papszTokens[1]);
     314             200 :         else if( EQUAL(papszTokens[0],"Start hour") )
     315               2 :             nStartHour = atoi(papszTokens[1]);
     316             198 :         else if( EQUAL(papszTokens[0],"Start minute") )
     317               2 :             nStartMinute = atoi(papszTokens[1]);
     318             196 :         else if( EQUAL(papszTokens[0],"Start second") )
     319               2 :             nStartSecond = atoi(papszTokens[1]);
     320                 : 
     321             194 :         else if( EQUAL(papszTokens[0],"Stop year") )
     322               2 :             nStopYear = atoi(papszTokens[1]);
     323             192 :         else if( EQUAL(papszTokens[0],"Stop month") )
     324               2 :             nStopMonth = atoi(papszTokens[1]);
     325             190 :         else if( EQUAL(papszTokens[0],"Stop day") )
     326               2 :             nStopDay = atoi(papszTokens[1]);
     327             188 :         else if( EQUAL(papszTokens[0],"Stop hour") )
     328               2 :             nStopHour = atoi(papszTokens[1]);
     329             186 :         else if( EQUAL(papszTokens[0],"Stop minute") )
     330               2 :             nStopMinute = atoi(papszTokens[1]);
     331             184 :         else if( EQUAL(papszTokens[0],"Stop second") )
     332               2 :             nStopSecond = atoi(papszTokens[1]);
     333                 : 
     334             182 :         else if( EQUAL(papszTokens[0],"Number of columns") )
     335                 :         {
     336               2 :             nCols = atoi(papszTokens[1]);
     337                 :         }
     338             180 :         else if( EQUAL(papszTokens[0],"Number of rows") )
     339                 :         {
     340               2 :             nRows = atoi(papszTokens[1]);
     341                 :         }
     342             178 :         else if( EQUAL(papszTokens[0],"Data type"))
     343                 :         {
     344               2 :             bIsInteger = EQUAL(papszTokens[1],"integer");
     345                 :         }
     346             176 :         else if( EQUAL(papszTokens[0],"Data bytes per pixel"))
     347                 :         {
     348               2 :             bIs2Bytes = EQUAL(papszTokens[1],"2");
     349                 :         }
     350             174 :         else if( EQUAL(papszTokens[0],"Projected"))
     351                 :         {
     352               2 :             bNotProjected = EQUAL(papszTokens[1],"no");
     353                 :         }
     354             172 :         else if( EQUAL(papszTokens[0],"Horizontal datum"))
     355                 :         {
     356               2 :             bIsWGS84 = EQUAL(papszTokens[1],"WGS84");
     357                 :         }
     358             170 :         else if( EQUAL(papszTokens[0],"No data value"))
     359                 :         {
     360               2 :             bHasNoData = TRUE;
     361               2 :             dfNoData = CPLAtofM(papszTokens[1]);
     362                 :         }
     363             168 :         else if( EQUAL(papszTokens[0],"Minimum data value"))
     364                 :         {
     365               2 :             bHasMin = TRUE;
     366               2 :             dfMin = CPLAtofM(papszTokens[1]);
     367                 :         }
     368             166 :         else if( EQUAL(papszTokens[0],"Maximum data value"))
     369                 :         {
     370               2 :             bHasMax = TRUE;
     371               2 :             dfMax = CPLAtofM(papszTokens[1]);
     372                 :         }
     373             164 :         else if( EQUAL(papszTokens[0],"Minimum x-axis coordinate") )
     374                 :         {
     375               2 :             bHasMinX = TRUE;
     376               2 :             dfMinX = CPLAtofM(papszTokens[1]);
     377                 :         }
     378             162 :         else if( EQUAL(papszTokens[0],"Minimum y-axis coordinate") )
     379                 :         {
     380               2 :             bHasMinY = TRUE;
     381               2 :             dfMinY = CPLAtofM(papszTokens[1]);
     382                 :         }
     383             160 :         else if( EQUAL(papszTokens[0],"Maximum x-axis coordinate") )
     384                 :         {
     385               2 :             bHasMaxX = TRUE;
     386               2 :             dfMaxX = CPLAtofM(papszTokens[1]);
     387                 :         }
     388             158 :         else if( EQUAL(papszTokens[0],"Maximum y-axis coordinate") )
     389                 :         {
     390               2 :             bHasMaxY = TRUE;
     391               2 :             dfMaxY = CPLAtofM(papszTokens[1]);
     392                 :         }
     393                 : 
     394             212 :         CSLDestroy( papszTokens );
     395                 :     }
     396                 : 
     397               2 :     VSIFCloseL( fp );
     398                 : 
     399                 : /* -------------------------------------------------------------------- */
     400                 : /*      Did we get the required keywords?  If not we return with        */
     401                 : /*      this never having been considered to be a match. This isn't     */
     402                 : /*      an error!                                                       */
     403                 : /* -------------------------------------------------------------------- */
     404               2 :     if( nRows == -1 || nCols == -1 || !bIsInteger || !bIs2Bytes )
     405               0 :         return NULL;
     406                 : 
     407               2 :     if( !bNotProjected || !bIsWGS84 )
     408               0 :         return NULL;
     409                 : 
     410               2 :     if( osDataFilename.size() == 0 )
     411               0 :         return NULL;
     412                 : 
     413               2 :     if (!GDALCheckDatasetDimensions(nCols, nRows))
     414               0 :         return NULL;
     415                 : 
     416                 : /* -------------------------------------------------------------------- */
     417                 : /*      Open target binary file.                                        */
     418                 : /* -------------------------------------------------------------------- */
     419               2 :     const char* pszPath = CPLGetPath(poOpenInfo->pszFilename);
     420               2 :     osDataFilename = CPLFormFilename(pszPath, osDataFilename, NULL);
     421                 : 
     422               2 :     VSILFILE* fpRaw = VSIFOpenL( osDataFilename, "rb" );
     423                 : 
     424               2 :     if( fpRaw == NULL )
     425               0 :         return NULL;
     426                 : 
     427                 : /* -------------------------------------------------------------------- */
     428                 : /*      Create a corresponding GDALDataset.                             */
     429                 : /* -------------------------------------------------------------------- */
     430                 :     SNODASDataset     *poDS;
     431                 : 
     432               2 :     poDS = new SNODASDataset();
     433                 : 
     434               2 :     poDS->nRasterXSize = nCols;
     435               2 :     poDS->nRasterYSize = nRows;
     436               2 :     poDS->osDataFilename = osDataFilename;
     437               2 :     poDS->bHasNoData = bHasNoData;
     438               2 :     poDS->dfNoData = dfNoData;
     439               2 :     poDS->bHasMin = bHasMin;
     440               2 :     poDS->dfMin = dfMin;
     441               2 :     poDS->bHasMax = bHasMax;
     442               2 :     poDS->dfMax = dfMax;
     443               2 :     if (bHasMinX && bHasMinY && bHasMaxX && bHasMaxY)
     444                 :     {
     445               2 :         poDS->bGotTransform = TRUE;
     446               2 :         poDS->adfGeoTransform[0] = dfMinX;
     447               2 :         poDS->adfGeoTransform[1] = (dfMaxX - dfMinX) / nCols;
     448               2 :         poDS->adfGeoTransform[2] = 0.0;
     449               2 :         poDS->adfGeoTransform[3] = dfMaxY;
     450               2 :         poDS->adfGeoTransform[4] = 0.0;
     451               2 :         poDS->adfGeoTransform[5] = - (dfMaxY - dfMinY) / nRows;
     452                 :     }
     453                 : 
     454               2 :     if (osDescription.size())
     455               2 :         poDS->SetMetadataItem("Description", osDescription);
     456               2 :     if (osDataUnits.size())
     457               2 :         poDS->SetMetadataItem("Data_Units", osDataUnits);
     458               2 :     if (nStartYear != -1 && nStartMonth != -1 && nStartDay != -1 &&
     459                 :         nStartHour != -1 && nStartMinute != -1 && nStartSecond != -1)
     460                 :         poDS->SetMetadataItem("Start_Date",
     461                 :                               CPLSPrintf("%04d/%02d/%02d %02d:%02d:%02d",
     462                 :                                         nStartYear, nStartMonth, nStartDay,
     463               2 :                                         nStartHour, nStartMinute, nStartSecond));
     464               2 :     if (nStopYear != -1 && nStopMonth != -1 && nStopDay != -1 &&
     465                 :         nStopHour != -1 && nStopMinute != -1 && nStopSecond != -1)
     466                 :         poDS->SetMetadataItem("Stop_Date",
     467                 :                               CPLSPrintf("%04d/%02d/%02d %02d:%02d:%02d",
     468                 :                                         nStopYear, nStopMonth, nStopDay,
     469               2 :                                         nStopHour, nStopMinute, nStopSecond));
     470                 : 
     471                 : /* -------------------------------------------------------------------- */
     472                 : /*      Create band information objects.                                */
     473                 : /* -------------------------------------------------------------------- */
     474               2 :     poDS->SetBand( 1, new SNODASRasterBand( fpRaw, nCols, nRows) );
     475                 : 
     476                 : /* -------------------------------------------------------------------- */
     477                 : /*      Initialize any PAM information.                                 */
     478                 : /* -------------------------------------------------------------------- */
     479               2 :     poDS->SetDescription( poOpenInfo->pszFilename );
     480               2 :     poDS->TryLoadXML();
     481                 : 
     482                 : /* -------------------------------------------------------------------- */
     483                 : /*      Check for overviews.                                            */
     484                 : /* -------------------------------------------------------------------- */
     485               2 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     486                 :    
     487               2 :     return( poDS );
     488                 : }
     489                 : 
     490                 : /************************************************************************/
     491                 : /*                       GDALRegister_SNODAS()                          */
     492                 : /************************************************************************/
     493                 : 
     494             582 : void GDALRegister_SNODAS()
     495                 : 
     496                 : {
     497                 :     GDALDriver  *poDriver;
     498                 : 
     499             582 :     if( GDALGetDriverByName( "SNODAS" ) == NULL )
     500                 :     {
     501             561 :         poDriver = new GDALDriver();
     502                 : 
     503             561 :         poDriver->SetDescription( "SNODAS" );
     504                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
     505             561 :                                    "Snow Data Assimilation System" );
     506                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
     507             561 :                                    "frmt_various.html#SNODAS" );
     508             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "hdr" );
     509                 : 
     510             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     511             561 :         poDriver->pfnOpen = SNODASDataset::Open;
     512             561 :         poDriver->pfnIdentify = SNODASDataset::Identify;
     513                 : 
     514             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     515                 :     }
     516             582 : }

Generated by: LCOV version 1.7