LCOV - code coverage report
Current view: top level - frmts/raw - eirdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 128 209 61.2 %
Date: 2024-11-21 22:18:42 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Erdas EIR Raw Driver
       4             :  * Purpose:  Implementation of EIRDataset
       5             :  * Author:   Adam Milling, amilling@alumni.uwaterloo.ca
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "gdal_frmts.h"
      16             : #include "ogr_spatialref.h"
      17             : #include "rawdataset.h"
      18             : 
      19             : #include <limits>
      20             : 
      21             : /************************************************************************/
      22             : /* ==================================================================== */
      23             : /*              EIRDataset                                              */
      24             : /* ==================================================================== */
      25             : /************************************************************************/
      26             : 
      27           2 : class EIRDataset final : public RawDataset
      28             : {
      29             :     friend class RawRasterBand;
      30             : 
      31             :     VSILFILE *fpImage = nullptr;  // image data file
      32             :     bool bGotTransform = false;
      33             :     double adfGeoTransform[6] = {0, 0, 0, 0, 0, 0};
      34             :     bool bHDRDirty = false;
      35             :     CPLStringList aosHDR{};
      36             :     char **papszExtraFiles = nullptr;
      37             : 
      38             :     void ResetKeyValue(const char *pszKey, const char *pszValue);
      39             : #ifdef unused
      40             :     const char *GetKeyValue(const char *pszKey, const char *pszDefault = "");
      41             : #endif
      42             : 
      43             :     CPL_DISALLOW_COPY_ASSIGN(EIRDataset)
      44             : 
      45             :     CPLErr Close() override;
      46             : 
      47             :   public:
      48             :     EIRDataset();
      49             :     ~EIRDataset() override;
      50             : 
      51             :     CPLErr GetGeoTransform(double *padfTransform) override;
      52             : 
      53             :     char **GetFileList() override;
      54             : 
      55             :     static int Identify(GDALOpenInfo *);
      56             :     static GDALDataset *Open(GDALOpenInfo *);
      57             : };
      58             : 
      59             : /************************************************************************/
      60             : /* ==================================================================== */
      61             : /*                            EIRDataset                                */
      62             : /* ==================================================================== */
      63             : /************************************************************************/
      64             : 
      65             : /************************************************************************/
      66             : /*                            EIRDataset()                             */
      67             : /************************************************************************/
      68             : 
      69             : EIRDataset::EIRDataset() = default;
      70             : 
      71             : /************************************************************************/
      72             : /*                            ~EIRDataset()                            */
      73             : /************************************************************************/
      74             : 
      75           4 : EIRDataset::~EIRDataset()
      76             : 
      77             : {
      78           2 :     EIRDataset::Close();
      79           4 : }
      80             : 
      81             : /************************************************************************/
      82             : /*                              Close()                                 */
      83             : /************************************************************************/
      84             : 
      85           4 : CPLErr EIRDataset::Close()
      86             : {
      87           4 :     CPLErr eErr = CE_None;
      88           4 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
      89             :     {
      90           2 :         if (EIRDataset::FlushCache(true) != CE_None)
      91           0 :             eErr = CE_Failure;
      92             : 
      93           2 :         if (nBands > 0 && GetAccess() == GA_Update)
      94             :         {
      95             :             RawRasterBand *poBand =
      96           0 :                 reinterpret_cast<RawRasterBand *>(GetRasterBand(1));
      97             : 
      98           0 :             int bNoDataSet = FALSE;
      99           0 :             const double dfNoData = poBand->GetNoDataValue(&bNoDataSet);
     100           0 :             if (bNoDataSet)
     101             :             {
     102           0 :                 ResetKeyValue("NODATA", CPLString().Printf("%.8g", dfNoData));
     103             :             }
     104             :         }
     105             : 
     106           2 :         if (fpImage)
     107             :         {
     108           2 :             if (VSIFCloseL(fpImage) != 0)
     109           0 :                 eErr = CE_Failure;
     110             :         }
     111             : 
     112           2 :         CSLDestroy(papszExtraFiles);
     113             : 
     114           2 :         if (GDALPamDataset::Close() != CE_None)
     115           0 :             eErr = CE_Failure;
     116             :     }
     117           4 :     return eErr;
     118             : }
     119             : 
     120             : #ifdef unused
     121             : /************************************************************************/
     122             : /*                            GetKeyValue()                             */
     123             : /************************************************************************/
     124             : 
     125             : const char *EIRDataset::GetKeyValue(const char *pszKey, const char *pszDefault)
     126             : 
     127             : {
     128             :     const char *const *papszHDR = aosHDR.List();
     129             :     for (int i = 0; papszHDR[i] != nullptr; i++)
     130             :     {
     131             :         if (EQUALN(pszKey, papszHDR[i], strlen(pszKey)) &&
     132             :             isspace((unsigned char)papszHDR[i][strlen(pszKey)]))
     133             :         {
     134             :             const char *pszValue = papszHDR[i] + strlen(pszKey);
     135             :             while (isspace(static_cast<unsigned char>(*pszValue)))
     136             :                 pszValue++;
     137             : 
     138             :             return pszValue;
     139             :         }
     140             :     }
     141             : 
     142             :     return pszDefault;
     143             : }
     144             : #endif
     145             : 
     146             : /************************************************************************/
     147             : /*                           ResetKeyValue()                            */
     148             : /*                                                                      */
     149             : /*      Replace or add the keyword with the indicated value in the      */
     150             : /*      papszHDR list.                                                  */
     151             : /************************************************************************/
     152             : 
     153           0 : void EIRDataset::ResetKeyValue(const char *pszKey, const char *pszValue)
     154             : 
     155             : {
     156           0 :     if (strlen(pszValue) > 65)
     157             :     {
     158           0 :         CPLAssert(strlen(pszValue) <= 65);
     159           0 :         return;
     160             :     }
     161             : 
     162           0 :     char szNewLine[82] = {'\0'};
     163           0 :     snprintf(szNewLine, sizeof(szNewLine), "%-15s%s", pszKey, pszValue);
     164             : 
     165           0 :     char **papszHDR = aosHDR.List();
     166           0 :     for (int i = aosHDR.size() - 1; i >= 0; i--)
     167             :     {
     168           0 :         if (EQUALN(papszHDR[i], szNewLine, strlen(pszKey) + 1))
     169             :         {
     170           0 :             if (strcmp(papszHDR[i], szNewLine) != 0)
     171             :             {
     172           0 :                 CPLFree(papszHDR[i]);
     173           0 :                 papszHDR[i] = CPLStrdup(szNewLine);
     174           0 :                 bHDRDirty = true;
     175             :             }
     176           0 :             return;
     177             :         }
     178             :     }
     179             : 
     180           0 :     bHDRDirty = true;
     181           0 :     aosHDR.AddString(szNewLine);
     182             : }
     183             : 
     184             : /************************************************************************/
     185             : /*                          GetGeoTransform()                           */
     186             : /************************************************************************/
     187             : 
     188           0 : CPLErr EIRDataset::GetGeoTransform(double *padfTransform)
     189             : 
     190             : {
     191           0 :     if (bGotTransform)
     192             :     {
     193           0 :         memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     194           0 :         return CE_None;
     195             :     }
     196             : 
     197           0 :     return GDALPamDataset::GetGeoTransform(padfTransform);
     198             : }
     199             : 
     200             : /************************************************************************/
     201             : /*                            GetFileList()                             */
     202             : /************************************************************************/
     203             : 
     204           1 : char **EIRDataset::GetFileList()
     205             : 
     206             : {
     207             :     // Main data file, etc.
     208           1 :     char **papszFileList = GDALPamDataset::GetFileList();
     209             : 
     210             :     // Header file.
     211           1 :     papszFileList = CSLInsertStrings(papszFileList, -1, papszExtraFiles);
     212             : 
     213           1 :     return papszFileList;
     214             : }
     215             : 
     216             : /************************************************************************/
     217             : /*                              Identify()                              */
     218             : /************************************************************************/
     219             : 
     220       51570 : int EIRDataset::Identify(GDALOpenInfo *poOpenInfo)
     221             : 
     222             : {
     223       51570 :     if (poOpenInfo->nHeaderBytes < 100)
     224       48185 :         return FALSE;
     225             : 
     226        3385 :     if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     227             :                "IMAGINE_RAW_FILE") == nullptr)
     228        3381 :         return FALSE;
     229             : 
     230           4 :     return TRUE;
     231             : }
     232             : 
     233             : /************************************************************************/
     234             : /*                                Open()                                */
     235             : /************************************************************************/
     236             : 
     237           2 : GDALDataset *EIRDataset::Open(GDALOpenInfo *poOpenInfo)
     238             : 
     239             : {
     240           2 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
     241           0 :         return nullptr;
     242             : 
     243             :     /* header example and description
     244             : 
     245             :     IMAGINE_RAW_FILE // must be on first line, by itself
     246             :     WIDTH 581        // number of columns in the image
     247             :     HEIGHT 695       // number of rows in the image
     248             :     NUM_LAYERS 3     // number of spectral bands in the image; default 1
     249             :     PIXEL_FILES raw8_3n_ui_sanjack.bl // raster file
     250             :                                       // default: same name with no extension
     251             :     FORMAT BIL       // BIL BIP BSQ; default BIL
     252             :     DATATYPE U8      // U1 U2 U4 U8 U16 U32 S16 S32 F32 F64; default U8
     253             :     BYTE_ORDER       // LSB MSB; required for U16 U32 S16 S32 F32 F64
     254             :     DATA_OFFSET      // start of image data in raster file; default 0 bytes
     255             :     END_RAW_FILE     // end RAW file - stop reading
     256             : 
     257             :     For a true color image with three bands (R, G, B) stored using 8 bits
     258             :     for each pixel in each band, DATA_TYPE equals U8 and NUM_LAYERS equals
     259             :     3 for a total of 24 bits per pixel.
     260             : 
     261             :     Note that the current version of ERDAS Raw Raster Reader/Writer does
     262             :     not support the LAYER_SKIP_BYTES, RECORD_SKIP_BYTES, TILE_WIDTH and
     263             :     TILE_HEIGHT directives. Since the reader does not read the PIXEL_FILES
     264             :     directive, the reader always assumes that the raw binary file is the
     265             :     dataset, and the name of this file is the name of the header without the
     266             :     extension. Currently, the reader does not support multiple raw binary
     267             :     files in one dataset or a single file with both the header and the raw
     268             :     binary data at the same time.
     269             :     */
     270             : 
     271           2 :     int nRows = -1;
     272           2 :     int nCols = -1;
     273           2 :     int nBands = 1;
     274           2 :     int nSkipBytes = 0;
     275           2 :     int nLineCount = 0;
     276           2 :     GDALDataType eDataType = GDT_Byte;
     277           2 :     int nBits = 8;
     278           2 :     char chByteOrder = 'M';
     279           2 :     char szLayout[10] = "BIL";
     280           4 :     CPLStringList aosHDR;
     281             : 
     282             :     // default raster file: same name with no extension
     283           4 :     const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
     284           4 :     const CPLString osName = CPLGetBasename(poOpenInfo->pszFilename);
     285           4 :     CPLString osRasterFilename = CPLFormCIFilename(osPath, osName, "");
     286             : 
     287             :     // parse the header file
     288           2 :     const char *pszLine = nullptr;
     289           2 :     VSIRewindL(poOpenInfo->fpL);
     290          18 :     while ((pszLine = CPLReadLineL(poOpenInfo->fpL)) != nullptr)
     291             :     {
     292          18 :         nLineCount++;
     293             : 
     294          18 :         if ((nLineCount == 1) && !EQUAL(pszLine, "IMAGINE_RAW_FILE"))
     295             :         {
     296           0 :             return nullptr;
     297             :         }
     298             : 
     299          18 :         if ((nLineCount > 50) || EQUAL(pszLine, "END_RAW_FILE"))
     300             :         {
     301             :             break;
     302             :         }
     303             : 
     304          16 :         if (strlen(pszLine) > 1000)
     305           0 :             break;
     306             : 
     307          16 :         aosHDR.AddString(pszLine);
     308             : 
     309             :         const CPLStringList aosTokens(
     310          16 :             CSLTokenizeStringComplex(pszLine, " \t", TRUE, FALSE));
     311          16 :         if (aosTokens.size() < 2)
     312             :         {
     313           2 :             continue;
     314             :         }
     315             : 
     316          14 :         if (EQUAL(aosTokens[0], "WIDTH"))
     317             :         {
     318           2 :             nCols = atoi(aosTokens[1]);
     319             :         }
     320          12 :         else if (EQUAL(aosTokens[0], "HEIGHT"))
     321             :         {
     322           2 :             nRows = atoi(aosTokens[1]);
     323             :         }
     324          10 :         else if (EQUAL(aosTokens[0], "NUM_LAYERS"))
     325             :         {
     326           2 :             nBands = atoi(aosTokens[1]);
     327             :         }
     328           8 :         else if (EQUAL(aosTokens[0], "PIXEL_FILES"))
     329             :         {
     330           2 :             osRasterFilename = CPLFormCIFilename(osPath, aosTokens[1], "");
     331             :         }
     332           6 :         else if (EQUAL(aosTokens[0], "FORMAT"))
     333             :         {
     334           2 :             snprintf(szLayout, sizeof(szLayout), "%s", aosTokens[1]);
     335             :         }
     336           6 :         else if (EQUAL(aosTokens[0], "DATATYPE") ||
     337           2 :                  EQUAL(aosTokens[0], "DATA_TYPE"))
     338             :         {
     339           4 :             if (EQUAL(aosTokens[1], "U1") || EQUAL(aosTokens[1], "U2") ||
     340           4 :                 EQUAL(aosTokens[1], "U4") || EQUAL(aosTokens[1], "U8"))
     341             :             {
     342           2 :                 nBits = 8;
     343           2 :                 eDataType = GDT_Byte;
     344             :             }
     345           0 :             else if (EQUAL(aosTokens[1], "U16"))
     346             :             {
     347           0 :                 nBits = 16;
     348           0 :                 eDataType = GDT_UInt16;
     349             :             }
     350           0 :             else if (EQUAL(aosTokens[1], "U32"))
     351             :             {
     352           0 :                 nBits = 32;
     353           0 :                 eDataType = GDT_UInt32;
     354             :             }
     355           0 :             else if (EQUAL(aosTokens[1], "S16"))
     356             :             {
     357           0 :                 nBits = 16;
     358           0 :                 eDataType = GDT_Int16;
     359             :             }
     360           0 :             else if (EQUAL(aosTokens[1], "S32"))
     361             :             {
     362           0 :                 nBits = 32;
     363           0 :                 eDataType = GDT_Int32;
     364             :             }
     365           0 :             else if (EQUAL(aosTokens[1], "F32"))
     366             :             {
     367           0 :                 nBits = 32;
     368           0 :                 eDataType = GDT_Float32;
     369             :             }
     370           0 :             else if (EQUAL(aosTokens[1], "F64"))
     371             :             {
     372           0 :                 nBits = 64;
     373           0 :                 eDataType = GDT_Float64;
     374             :             }
     375             :             else
     376             :             {
     377           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     378             :                          "EIR driver does not support DATATYPE %s.",
     379             :                          aosTokens[1]);
     380           0 :                 return nullptr;
     381             :             }
     382             :         }
     383           2 :         else if (EQUAL(aosTokens[0], "BYTE_ORDER"))
     384             :         {
     385             :             // M for MSB, L for LSB
     386           0 :             chByteOrder = static_cast<char>(
     387           0 :                 toupper(static_cast<unsigned char>(aosTokens[1][0])));
     388             :         }
     389           2 :         else if (EQUAL(aosTokens[0], "DATA_OFFSET"))
     390             :         {
     391           2 :             nSkipBytes = atoi(aosTokens[1]);  // TBD: is this mapping right?
     392           2 :             if (nSkipBytes < 0)
     393             :             {
     394           0 :                 return nullptr;
     395             :             }
     396             :         }
     397             :     }
     398           2 :     CPL_IGNORE_RET_VAL(nBits);
     399             : 
     400             :     /* -------------------------------------------------------------------- */
     401             :     /*      Did we get the required keywords?  If not we return with        */
     402             :     /*      this never having been considered to be a match. This isn't     */
     403             :     /*      an error!                                                       */
     404             :     /* -------------------------------------------------------------------- */
     405           2 :     if (nRows <= 0 || nCols <= 0 || nBands <= 0)
     406             :     {
     407           0 :         return nullptr;
     408             :     }
     409             : 
     410           4 :     if (!GDALCheckDatasetDimensions(nCols, nRows) ||
     411           2 :         !GDALCheckBandCount(nBands, FALSE))
     412             :     {
     413           0 :         return nullptr;
     414             :     }
     415             : 
     416             :     /* -------------------------------------------------------------------- */
     417             :     /*      Confirm the requested access is supported.                      */
     418             :     /* -------------------------------------------------------------------- */
     419           2 :     if (poOpenInfo->eAccess == GA_Update)
     420             :     {
     421           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     422             :                  "The EIR driver does not support update access to existing"
     423             :                  " datasets.");
     424           0 :         return nullptr;
     425             :     }
     426             :     /* -------------------------------------------------------------------- */
     427             :     /*      Create a corresponding GDALDataset.                             */
     428             :     /* -------------------------------------------------------------------- */
     429           4 :     auto poDS = std::make_unique<EIRDataset>();
     430             : 
     431             :     /* -------------------------------------------------------------------- */
     432             :     /*      Capture some information from the file that is of interest.     */
     433             :     /* -------------------------------------------------------------------- */
     434           2 :     poDS->nRasterXSize = nCols;
     435           2 :     poDS->nRasterYSize = nRows;
     436           2 :     poDS->aosHDR = std::move(aosHDR);
     437             : 
     438             :     /* -------------------------------------------------------------------- */
     439             :     /*      Open target binary file.                                        */
     440             :     /* -------------------------------------------------------------------- */
     441           2 :     poDS->fpImage = VSIFOpenL(osRasterFilename.c_str(), "rb");
     442           2 :     if (poDS->fpImage == nullptr)
     443             :     {
     444           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open %s: %s",
     445           0 :                  osRasterFilename.c_str(), VSIStrerror(errno));
     446           0 :         return nullptr;
     447             :     }
     448           4 :     poDS->papszExtraFiles =
     449           2 :         CSLAddString(poDS->papszExtraFiles, osRasterFilename);
     450             : 
     451           2 :     poDS->eAccess = poOpenInfo->eAccess;
     452             : 
     453             :     /* -------------------------------------------------------------------- */
     454             :     /*      Compute the line offset.                                        */
     455             :     /* -------------------------------------------------------------------- */
     456           2 :     const int nItemSize = GDALGetDataTypeSizeBytes(eDataType);
     457           2 :     int nPixelOffset = 0;
     458           2 :     int nLineOffset = 0;
     459           2 :     vsi_l_offset nBandOffset = 0;
     460             : 
     461           2 :     if (EQUAL(szLayout, "BIP"))
     462             :     {
     463           0 :         nPixelOffset = nItemSize * nBands;
     464           0 :         if (nPixelOffset > INT_MAX / nCols)
     465             :         {
     466           0 :             return nullptr;
     467             :         }
     468           0 :         nLineOffset = nPixelOffset * nCols;
     469           0 :         nBandOffset = static_cast<vsi_l_offset>(nItemSize);
     470             :     }
     471           2 :     else if (EQUAL(szLayout, "BSQ"))
     472             :     {
     473           0 :         nPixelOffset = nItemSize;
     474           0 :         if (nPixelOffset > INT_MAX / nCols)
     475             :         {
     476           0 :             return nullptr;
     477             :         }
     478           0 :         nLineOffset = nPixelOffset * nCols;
     479           0 :         nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows;
     480             :     }
     481             :     else /* assume BIL */
     482             :     {
     483           2 :         nPixelOffset = nItemSize;
     484           2 :         if (nItemSize > INT_MAX / nBands ||
     485           2 :             nItemSize * nBands > INT_MAX / nCols)
     486             :         {
     487           0 :             return nullptr;
     488             :         }
     489           2 :         nLineOffset = nItemSize * nBands * nCols;
     490           2 :         nBandOffset = static_cast<vsi_l_offset>(nItemSize) * nCols;
     491             :     }
     492             : 
     493           2 :     if (poDS->nBands > 1)
     494             :     {
     495           0 :         if (nBandOffset >
     496           0 :                 std::numeric_limits<vsi_l_offset>::max() / (poDS->nBands - 1) ||
     497           0 :             static_cast<vsi_l_offset>(nSkipBytes) >
     498           0 :                 std::numeric_limits<vsi_l_offset>::max() -
     499           0 :                     nBandOffset * (poDS->nBands - 1))
     500             :         {
     501           0 :             return nullptr;
     502             :         }
     503             :     }
     504             : 
     505           2 :     if (!RAWDatasetCheckMemoryUsage(
     506           2 :             poDS->nRasterXSize, poDS->nRasterYSize, nBands, nItemSize,
     507           2 :             nPixelOffset, nLineOffset, nSkipBytes, nBandOffset, poDS->fpImage))
     508             :     {
     509           0 :         return nullptr;
     510             :     }
     511             : 
     512           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     513           2 :     poDS->PamInitialize();
     514             : 
     515             :     /* -------------------------------------------------------------------- */
     516             :     /*      Create band information objects.                                */
     517             :     /* -------------------------------------------------------------------- */
     518           4 :     for (int i = 0; i < nBands; i++)
     519             :     {
     520             :         auto poBand = RawRasterBand::Create(
     521           4 :             poDS.get(), i + 1, poDS->fpImage, nSkipBytes + nBandOffset * i,
     522             :             nPixelOffset, nLineOffset, eDataType,
     523             :             chByteOrder == 'I' || chByteOrder == 'L'
     524           2 :                 ? RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN
     525             :                 : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
     526           2 :             RawRasterBand::OwnFP::NO);
     527           2 :         if (!poBand)
     528           0 :             return nullptr;
     529           2 :         poDS->SetBand(i + 1, std::move(poBand));
     530             :     }
     531             : 
     532             :     /* -------------------------------------------------------------------- */
     533             :     /*      look for a worldfile                                            */
     534             :     /* -------------------------------------------------------------------- */
     535             : 
     536           2 :     if (!poDS->bGotTransform)
     537           2 :         poDS->bGotTransform = CPL_TO_BOOL(GDALReadWorldFile(
     538           2 :             poOpenInfo->pszFilename, nullptr, poDS->adfGeoTransform));
     539             : 
     540           2 :     if (!poDS->bGotTransform)
     541           2 :         poDS->bGotTransform = CPL_TO_BOOL(GDALReadWorldFile(
     542           2 :             poOpenInfo->pszFilename, "wld", poDS->adfGeoTransform));
     543             : 
     544             :     /* -------------------------------------------------------------------- */
     545             :     /*      Initialize any PAM information.                                 */
     546             :     /* -------------------------------------------------------------------- */
     547           2 :     poDS->TryLoadXML();
     548             : 
     549             :     /* -------------------------------------------------------------------- */
     550             :     /*      Check for overviews.                                            */
     551             :     /* -------------------------------------------------------------------- */
     552           2 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     553             : 
     554           2 :     return poDS.release();
     555             : }
     556             : 
     557             : /************************************************************************/
     558             : /*                         GDALRegister_EIR()                           */
     559             : /************************************************************************/
     560             : 
     561        1595 : void GDALRegister_EIR()
     562             : 
     563             : {
     564        1595 :     if (GDALGetDriverByName("EIR") != nullptr)
     565         302 :         return;
     566             : 
     567        1293 :     GDALDriver *poDriver = new GDALDriver();
     568             : 
     569        1293 :     poDriver->SetDescription("EIR");
     570        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     571        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Erdas Imagine Raw");
     572        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/eir.html");
     573        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     574             : 
     575        1293 :     poDriver->pfnOpen = EIRDataset::Open;
     576        1293 :     poDriver->pfnIdentify = EIRDataset::Identify;
     577             : 
     578        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     579             : }

Generated by: LCOV version 1.14