LCOV - code coverage report
Current view: directory - frmts/gif - biggifdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 150 121 80.7 %
Date: 2012-04-28 Functions: 18 10 55.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: biggifdataset.cpp 22684 2011-07-10 19:30:49Z rouault $
       3                 :  *
       4                 :  * Project:  BIGGIF Driver
       5                 :  * Purpose:  Implement GDAL support for reading large GIF files in a 
       6                 :  *           streaming fashion rather than the slurp-into-memory approach
       7                 :  *           of the normal GIF driver.
       8                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       9                 :  *
      10                 :  ******************************************************************************
      11                 :  * Copyright (c) 2001-2008, Frank Warmerdam <warmerdam@pobox.com>
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  *
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  *
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  ****************************************************************************/
      31                 : 
      32                 : #include "gdal_pam.h"
      33                 : #include "cpl_string.h"
      34                 : #include "gifabstractdataset.h"
      35                 : 
      36                 : CPL_CVSID("$Id: biggifdataset.cpp 22684 2011-07-10 19:30:49Z rouault $");
      37                 : 
      38                 : CPL_C_START
      39                 : void  GDALRegister_BIGGIF(void);
      40                 : CPL_C_END
      41                 : 
      42                 : static const int InterlacedOffset[] = { 0, 4, 2, 1 }; 
      43                 : static const int InterlacedJumps[] = { 8, 8, 4, 2 };  
      44                 : 
      45                 : static int VSIGIFReadFunc( GifFileType *, GifByteType *, int);
      46                 : 
      47                 : /************************************************************************/
      48                 : /* ==================================================================== */
      49                 : /*                          BIGGIFDataset                               */
      50                 : /* ==================================================================== */
      51                 : /************************************************************************/
      52                 : 
      53                 : class BIGGifRasterBand;
      54                 : 
      55                 : class BIGGIFDataset : public GIFAbstractDataset
      56                 : {
      57                 :     friend class BIGGifRasterBand;
      58                 : 
      59                 :     int         nLastLineRead;
      60                 : 
      61                 :     GDALDataset *poWorkDS;
      62                 : 
      63                 :     CPLErr       ReOpen();
      64                 : 
      65                 :   protected:
      66                 :     virtual int         CloseDependentDatasets();
      67                 : 
      68                 :   public:
      69                 :                  BIGGIFDataset();
      70                 :                  ~BIGGIFDataset();
      71                 : 
      72                 :     static GDALDataset *Open( GDALOpenInfo * );
      73                 : };
      74                 : 
      75                 : /************************************************************************/
      76                 : /* ==================================================================== */
      77                 : /*                            BIGGifRasterBand                          */
      78                 : /* ==================================================================== */
      79                 : /************************************************************************/
      80                 : 
      81                 : class BIGGifRasterBand : public GDALPamRasterBand
      82                 : {
      83                 :     friend class BIGGIFDataset;
      84                 : 
      85                 :     int   *panInterlaceMap;
      86                 :     
      87                 :     GDALColorTable *poColorTable;
      88                 : 
      89                 :   public:
      90                 : 
      91                 :                    BIGGifRasterBand( BIGGIFDataset *, int );
      92                 :     virtual       ~BIGGifRasterBand();
      93                 : 
      94                 :     virtual CPLErr IReadBlock( int, int, void * );
      95                 : 
      96                 :     virtual GDALColorInterp GetColorInterpretation();
      97                 :     virtual GDALColorTable *GetColorTable();
      98                 : };
      99                 : 
     100                 : /************************************************************************/
     101                 : /*                          BIGGifRasterBand()                          */
     102                 : /************************************************************************/
     103                 : 
     104               6 : BIGGifRasterBand::BIGGifRasterBand( BIGGIFDataset *poDS, int nBackground )
     105                 : 
     106                 : {
     107               6 :     SavedImage *psImage = poDS->hGifFile->SavedImages + 0;
     108                 : 
     109               6 :     this->poDS = poDS;
     110               6 :     this->nBand = 1;
     111                 : 
     112               6 :     eDataType = GDT_Byte;
     113                 : 
     114               6 :     nBlockXSize = poDS->nRasterXSize;
     115               6 :     nBlockYSize = 1;
     116                 : 
     117                 : /* -------------------------------------------------------------------- */
     118                 : /*      Setup interlacing map if required.                              */
     119                 : /* -------------------------------------------------------------------- */
     120               6 :     panInterlaceMap = NULL;
     121               6 :     if( psImage->ImageDesc.Interlace )
     122                 :     {
     123               6 :         int i, j, iLine = 0;
     124                 : 
     125               6 :         poDS->SetMetadataItem( "INTERLACED", "YES", "IMAGE_STRUCTURE" );
     126                 : 
     127               6 :         panInterlaceMap = (int *) CPLCalloc(poDS->nRasterYSize,sizeof(int));
     128                 : 
     129              30 :   for (i = 0; i < 4; i++)
     130                 :         {
     131          134292 :       for (j = InterlacedOffset[i]; 
     132                 :                  j < poDS->nRasterYSize;
     133           67134 :                  j += InterlacedJumps[i]) 
     134           67134 :                 panInterlaceMap[j] = iLine++;
     135                 :         }
     136                 :     }
     137                 :     else
     138               0 :         poDS->SetMetadataItem( "INTERLACED", "NO", "IMAGE_STRUCTURE" );
     139                 : 
     140                 : /* -------------------------------------------------------------------- */
     141                 : /*      Setup colormap.                                                 */
     142                 : /* -------------------------------------------------------------------- */
     143               6 :     ColorMapObject  *psGifCT = psImage->ImageDesc.ColorMap;
     144               6 :     if( psGifCT == NULL )
     145               6 :         psGifCT = poDS->hGifFile->SColorMap;
     146                 : 
     147               6 :     poColorTable = new GDALColorTable();
     148             102 :     for( int iColor = 0; iColor < psGifCT->ColorCount; iColor++ )
     149                 :     {
     150                 :         GDALColorEntry  oEntry;
     151                 : 
     152              96 :         oEntry.c1 = psGifCT->Colors[iColor].Red;
     153              96 :         oEntry.c2 = psGifCT->Colors[iColor].Green;
     154              96 :         oEntry.c3 = psGifCT->Colors[iColor].Blue;
     155              96 :         oEntry.c4 = 255;
     156                 : 
     157              96 :         poColorTable->SetColorEntry( iColor, &oEntry );
     158                 :     }
     159                 : 
     160                 : /* -------------------------------------------------------------------- */
     161                 : /*      If we have a background value, return it here.  Some            */
     162                 : /*      applications might want to treat this as transparent, but in    */
     163                 : /*      many uses this is inappropriate so we don't return it as        */
     164                 : /*      nodata or transparent.                                          */
     165                 : /* -------------------------------------------------------------------- */
     166               6 :     if( nBackground != 255 )
     167                 :     {
     168                 :         char szBackground[10];
     169                 :         
     170               6 :         sprintf( szBackground, "%d", nBackground );
     171               6 :         SetMetadataItem( "GIF_BACKGROUND", szBackground );
     172                 :     }
     173               6 : }
     174                 : 
     175                 : /************************************************************************/
     176                 : /*                           ~BIGGifRasterBand()                           */
     177                 : /************************************************************************/
     178                 : 
     179               6 : BIGGifRasterBand::~BIGGifRasterBand()
     180                 : 
     181                 : {
     182               6 :     if( poColorTable != NULL )
     183               6 :         delete poColorTable;
     184                 : 
     185               6 :     CPLFree( panInterlaceMap );
     186               6 : }
     187                 : 
     188                 : /************************************************************************/
     189                 : /*                             IReadBlock()                             */
     190                 : /************************************************************************/
     191                 : 
     192             800 : CPLErr BIGGifRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     193                 :                                   void * pImage )
     194                 : 
     195                 : {
     196             800 :     BIGGIFDataset *poGDS = (BIGGIFDataset *) poDS;
     197                 : 
     198             800 :     CPLAssert( nBlockXOff == 0 );
     199                 : 
     200             800 :     if( panInterlaceMap != NULL )
     201             800 :         nBlockYOff = panInterlaceMap[nBlockYOff];
     202                 : 
     203                 : /* -------------------------------------------------------------------- */
     204                 : /*      Do we already have this line in the work dataset?               */
     205                 : /* -------------------------------------------------------------------- */
     206             800 :     if( poGDS->poWorkDS != NULL && nBlockYOff <= poGDS->nLastLineRead )
     207                 :     {
     208                 :         return poGDS->poWorkDS->
     209                 :             RasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1, 
     210                 :                       pImage, nBlockXSize, 1, GDT_Byte, 
     211             396 :                       1, NULL, 0, 0, 0 );
     212                 :     }
     213                 : 
     214                 : /* -------------------------------------------------------------------- */
     215                 : /*      Do we need to restart from the start of the image?              */
     216                 : /* -------------------------------------------------------------------- */
     217             404 :     if( nBlockYOff <= poGDS->nLastLineRead )
     218                 :     {
     219               2 :         if( poGDS->ReOpen() == CE_Failure )
     220               0 :             return CE_Failure;
     221                 :     }
     222                 : 
     223                 : /* -------------------------------------------------------------------- */
     224                 : /*      Read till we get our target line.                               */
     225                 : /* -------------------------------------------------------------------- */
     226            2010 :     while( poGDS->nLastLineRead < nBlockYOff )
     227                 :     {
     228            1202 :         if( DGifGetLine( poGDS->hGifFile, (GifPixelType*)pImage, 
     229                 :                          nBlockXSize ) == GIF_ERROR )
     230                 :         {
     231                 :             CPLError( CE_Failure, CPLE_AppDefined,
     232               0 :                       "Failure decoding scanline of GIF file." );
     233               0 :             return CE_Failure;
     234                 :         }
     235                 : 
     236            1202 :         poGDS->nLastLineRead++;
     237                 : 
     238            1202 :         if( poGDS->poWorkDS != NULL )
     239                 :         {
     240                 :             poGDS->poWorkDS->RasterIO( GF_Write, 
     241                 :                                        0, poGDS->nLastLineRead, nBlockXSize, 1, 
     242                 :                                        pImage, nBlockXSize, 1, GDT_Byte, 
     243             800 :                                        1, NULL, 0, 0, 0 );
     244                 :         }
     245                 :     }
     246                 : 
     247             404 :     return CE_None;
     248                 : }
     249                 : 
     250                 : /************************************************************************/
     251                 : /*                       GetColorInterpretation()                       */
     252                 : /************************************************************************/
     253                 : 
     254               0 : GDALColorInterp BIGGifRasterBand::GetColorInterpretation()
     255                 : 
     256                 : {
     257               0 :     return GCI_PaletteIndex;
     258                 : }
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                           GetColorTable()                            */
     262                 : /************************************************************************/
     263                 : 
     264               0 : GDALColorTable *BIGGifRasterBand::GetColorTable()
     265                 : 
     266                 : {
     267               0 :     return poColorTable;
     268                 : }
     269                 : 
     270                 : /************************************************************************/
     271                 : /* ==================================================================== */
     272                 : /*                             BIGGIFDataset                            */
     273                 : /* ==================================================================== */
     274                 : /************************************************************************/
     275                 : 
     276                 : 
     277                 : /************************************************************************/
     278                 : /*                            BIGGIFDataset()                            */
     279                 : /************************************************************************/
     280                 : 
     281               6 : BIGGIFDataset::BIGGIFDataset()
     282                 : 
     283                 : {
     284               6 :     nLastLineRead = -1;
     285               6 :     poWorkDS = NULL;
     286               6 : }
     287                 : 
     288                 : /************************************************************************/
     289                 : /*                           ~BIGGIFDataset()                            */
     290                 : /************************************************************************/
     291                 : 
     292               6 : BIGGIFDataset::~BIGGIFDataset()
     293                 : 
     294                 : {
     295               6 :     FlushCache();
     296                 : 
     297               6 :     CloseDependentDatasets();
     298               6 : }
     299                 : 
     300                 : /************************************************************************/
     301                 : /*                      CloseDependentDatasets()                        */
     302                 : /************************************************************************/
     303                 : 
     304               6 : int BIGGIFDataset::CloseDependentDatasets()
     305                 : {
     306               6 :     int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
     307                 : 
     308               6 :     if( poWorkDS != NULL )
     309                 :     {
     310               2 :         bHasDroppedRef = TRUE;
     311                 : 
     312               2 :         CPLString osTempFilename = poWorkDS->GetDescription();
     313                 : 
     314               2 :         GDALClose( (GDALDatasetH) poWorkDS );
     315               2 :         poWorkDS = NULL;
     316                 : 
     317               2 :         GDALDriver *poGTiff = (GDALDriver *) GDALGetDriverByName( "GTiff" );
     318               2 :         poGTiff->Delete( osTempFilename );
     319                 : 
     320               2 :         poWorkDS = NULL;
     321                 :     }
     322                 : 
     323               6 :     return bHasDroppedRef;
     324                 : }
     325                 : 
     326                 : /************************************************************************/
     327                 : /*                               ReOpen()                               */
     328                 : /*                                                                      */
     329                 : /*      (Re)Open the gif file and process past the first image          */
     330                 : /*      descriptor.                                                     */
     331                 : /************************************************************************/
     332                 : 
     333               8 : CPLErr BIGGIFDataset::ReOpen()
     334                 : 
     335                 : {
     336                 : /* -------------------------------------------------------------------- */
     337                 : /*      If the file is already open, close it so we can restart.        */
     338                 : /* -------------------------------------------------------------------- */
     339               8 :     if( hGifFile != NULL )
     340               2 :         DGifCloseFile( hGifFile );
     341                 : 
     342                 : /* -------------------------------------------------------------------- */
     343                 : /*      If we are actually reopening, then we assume that access to     */
     344                 : /*      the image data is not strictly once through sequential, and     */
     345                 : /*      we will try to create a working database in a temporary         */
     346                 : /*      directory to hold the image as we read through it the second    */
     347                 : /*      time.                                                           */
     348                 : /* -------------------------------------------------------------------- */
     349               8 :     if( hGifFile != NULL )
     350                 :     {
     351               2 :         GDALDriver *poGTiffDriver = (GDALDriver*) GDALGetDriverByName("GTiff");
     352                 :         
     353               2 :         if( poGTiffDriver != NULL )
     354                 :         {
     355                 :             /* Create as a sparse file to avoid filling up the whole file */
     356                 :             /* while closing and then destroying this temporary dataset */
     357               2 :             const char* apszOptions[] = { "COMPRESS=LZW", "SPARSE_OK=YES", NULL };
     358               2 :             CPLString osTempFilename = CPLGenerateTempFilename("biggif");
     359                 : 
     360               2 :             osTempFilename += ".tif";
     361                 : 
     362                 :             poWorkDS = poGTiffDriver->Create( osTempFilename, 
     363                 :                                               nRasterXSize, nRasterYSize, 1, 
     364               2 :                                               GDT_Byte, const_cast<char**>(apszOptions));
     365                 :         }
     366                 :     }
     367                 : 
     368                 : /* -------------------------------------------------------------------- */
     369                 : /*      Open                                                            */
     370                 : /* -------------------------------------------------------------------- */
     371               8 :     VSIFSeekL( fp, 0, SEEK_SET );
     372                 : 
     373               8 :     nLastLineRead = -1;
     374               8 :     hGifFile = DGifOpen( fp, VSIGIFReadFunc );
     375               8 :     if( hGifFile == NULL )
     376                 :     {
     377                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     378               0 :                   "DGifOpen() failed.  Perhaps the gif file is corrupt?\n" );
     379                 : 
     380               0 :         return CE_Failure;
     381                 :     }
     382                 : 
     383                 : /* -------------------------------------------------------------------- */
     384                 : /*      Find the first image record.                                    */
     385                 : /* -------------------------------------------------------------------- */
     386               8 :     GifRecordType RecordType = TERMINATE_RECORD_TYPE;
     387                 : 
     388              16 :     while( DGifGetRecordType(hGifFile, &RecordType) != GIF_ERROR
     389                 :            && RecordType != TERMINATE_RECORD_TYPE
     390                 :            && RecordType != IMAGE_DESC_RECORD_TYPE )
     391                 :     {
     392                 :         /* Skip extension records found before IMAGE_DESC_RECORD_TYPE */
     393               0 :         if (RecordType == EXTENSION_RECORD_TYPE)
     394                 :         {
     395                 :             int nFunction;
     396                 :             GifByteType *pExtData;
     397               0 :             if (DGifGetExtension(hGifFile, &nFunction, &pExtData) == GIF_ERROR)
     398               0 :                 break;
     399               0 :             while (pExtData != NULL)
     400                 :             {
     401               0 :                 if (DGifGetExtensionNext(hGifFile, &pExtData) == GIF_ERROR)
     402               0 :                     break;
     403                 :             }
     404                 :         }
     405                 :     }
     406                 : 
     407               8 :     if( RecordType != IMAGE_DESC_RECORD_TYPE )
     408                 :     {
     409               0 :         DGifCloseFile( hGifFile );
     410               0 :         hGifFile = NULL;
     411                 : 
     412                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     413               0 :                   "Failed to find image description record in GIF file." );
     414               0 :         return CE_Failure;
     415                 :     }
     416                 :     
     417               8 :     if (DGifGetImageDesc(hGifFile) == GIF_ERROR)
     418                 :     {
     419               0 :         DGifCloseFile( hGifFile );
     420               0 :         hGifFile = NULL;
     421                 : 
     422                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     423               0 :                   "Image description reading failed in GIF file." );
     424               0 :         return CE_Failure;
     425                 :     }
     426                 :     
     427               8 :     return CE_None;
     428                 : }
     429                 : 
     430                 : 
     431                 : /************************************************************************/
     432                 : /*                                Open()                                */
     433                 : /************************************************************************/
     434                 : 
     435            5056 : GDALDataset *BIGGIFDataset::Open( GDALOpenInfo * poOpenInfo )
     436                 : 
     437                 : {
     438            5056 :     if( !Identify( poOpenInfo ) )
     439            5050 :         return NULL;
     440                 : 
     441               6 :     if( poOpenInfo->eAccess == GA_Update )
     442                 :     {
     443                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     444                 :                   "The GIF driver does not support update access to existing"
     445               0 :                   " files.\n" );
     446               0 :         return NULL;
     447                 :     }
     448                 : 
     449                 : /* -------------------------------------------------------------------- */
     450                 : /*      Open the file.                                                  */
     451                 : /* -------------------------------------------------------------------- */
     452                 :     VSILFILE                *fp;
     453                 : 
     454               6 :     fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
     455               6 :     if( fp == NULL )
     456               0 :         return NULL;
     457                 : 
     458                 : /* -------------------------------------------------------------------- */
     459                 : /*      Create a corresponding GDALDataset.                             */
     460                 : /* -------------------------------------------------------------------- */
     461                 :     BIGGIFDataset   *poDS;
     462                 : 
     463               6 :     poDS = new BIGGIFDataset();
     464                 : 
     465               6 :     poDS->fp = fp;
     466               6 :     poDS->eAccess = GA_ReadOnly;
     467               6 :     if( poDS->ReOpen() == CE_Failure )
     468                 :     {
     469               0 :         delete poDS;
     470               0 :         return NULL;
     471                 :     }
     472                 : 
     473                 : /* -------------------------------------------------------------------- */
     474                 : /*      Capture some information from the file that is of interest.     */
     475                 : /* -------------------------------------------------------------------- */
     476                 :     
     477               6 :     poDS->nRasterXSize = poDS->hGifFile->SavedImages[0].ImageDesc.Width;
     478               6 :     poDS->nRasterYSize = poDS->hGifFile->SavedImages[0].ImageDesc.Height;
     479                 : 
     480                 : /* -------------------------------------------------------------------- */
     481                 : /*      Create band information objects.                                */
     482                 : /* -------------------------------------------------------------------- */
     483                 :     poDS->SetBand( 1, 
     484                 :                    new BIGGifRasterBand( poDS, 
     485               6 :                                          poDS->hGifFile->SBackGroundColor ));
     486                 : 
     487                 : /* -------------------------------------------------------------------- */
     488                 : /*      Check for georeferencing.                                       */
     489                 : /* -------------------------------------------------------------------- */
     490               6 :     poDS->DetectGeoreferencing(poOpenInfo);
     491                 : 
     492                 : /* -------------------------------------------------------------------- */
     493                 : /*      Initialize any PAM information.                                 */
     494                 : /* -------------------------------------------------------------------- */
     495               6 :     poDS->SetDescription( poOpenInfo->pszFilename );
     496               6 :     poDS->TryLoadXML();
     497                 : 
     498                 : /* -------------------------------------------------------------------- */
     499                 : /*      Support overviews.                                              */
     500                 : /* -------------------------------------------------------------------- */
     501               6 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     502                 : 
     503               6 :     return poDS;
     504                 : }
     505                 : 
     506                 : /************************************************************************/
     507                 : /*                           VSIGIFReadFunc()                           */
     508                 : /*                                                                      */
     509                 : /*      Proxy function for reading from GIF file.                       */
     510                 : /************************************************************************/
     511                 : 
     512             390 : static int VSIGIFReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
     513                 :                            int nBytesToRead )
     514                 : 
     515                 : {
     516                 :     return VSIFReadL( pabyBuffer, 1, nBytesToRead, 
     517             390 :                       (VSILFILE *) psGFile->UserData );
     518                 : }
     519                 : 
     520                 : /************************************************************************/
     521                 : /*                        GDALRegister_BIGGIF()                         */
     522                 : /************************************************************************/
     523                 : 
     524            1135 : void GDALRegister_BIGGIF()
     525                 : 
     526                 : {
     527                 :     GDALDriver  *poDriver;
     528                 : 
     529            1135 :     if( GDALGetDriverByName( "BIGGIF" ) == NULL )
     530                 :     {
     531            1093 :         poDriver = new GDALDriver();
     532                 :         
     533            1093 :         poDriver->SetDescription( "BIGGIF" );
     534                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     535            1093 :                                    "Graphics Interchange Format (.gif)" );
     536                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     537            1093 :                                    "frmt_gif.html" );
     538            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gif" );
     539            1093 :         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/gif" );
     540            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     541                 : 
     542            1093 :         poDriver->pfnOpen = BIGGIFDataset::Open;
     543            1093 :         poDriver->pfnIdentify = GIFAbstractDataset::Identify;
     544                 : 
     545            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     546                 :     }
     547            1135 : }
     548                 : 

Generated by: LCOV version 1.7