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

Generated by: LCOV version 1.14