LCOV - code coverage report
Current view: top level - frmts/raw - genbindataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 188 296 63.5 %
Date: 2025-01-18 12:42:00 Functions: 10 14 71.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Generic Binary format driver (.hdr but not ESRI .hdr!)
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2008-2011, 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 <algorithm>
      20             : #include <cstdlib>
      21             : 
      22             : #include "usgs_esri_zones.h"
      23             : 
      24             : /************************************************************************/
      25             : /* ==================================================================== */
      26             : /*                              GenBinDataset                           */
      27             : /* ==================================================================== */
      28             : /************************************************************************/
      29             : 
      30             : class GenBinDataset final : public RawDataset
      31             : {
      32             :     friend class GenBinBitRasterBand;
      33             : 
      34             :     VSILFILE *fpImage;  // image data file.
      35             : 
      36             :     bool bGotTransform;
      37             :     double adfGeoTransform[6];
      38             :     OGRSpatialReference m_oSRS{};
      39             : 
      40             :     char **papszHDR;
      41             : 
      42             :     void ParseCoordinateSystem(char **);
      43             : 
      44             :     CPL_DISALLOW_COPY_ASSIGN(GenBinDataset)
      45             : 
      46             :     CPLErr Close() override;
      47             : 
      48             :   public:
      49             :     GenBinDataset();
      50             :     ~GenBinDataset() override;
      51             : 
      52             :     CPLErr GetGeoTransform(double *padfTransform) override;
      53             : 
      54           1 :     const OGRSpatialReference *GetSpatialRef() const override
      55             :     {
      56           1 :         return m_oSRS.IsEmpty() ? RawDataset::GetSpatialRef() : &m_oSRS;
      57             :     }
      58             : 
      59             :     char **GetFileList() override;
      60             : 
      61             :     static GDALDataset *Open(GDALOpenInfo *);
      62             : };
      63             : 
      64             : /************************************************************************/
      65             : /* ==================================================================== */
      66             : /*                       GenBinBitRasterBand                            */
      67             : /* ==================================================================== */
      68             : /************************************************************************/
      69             : 
      70             : class GenBinBitRasterBand final : public GDALPamRasterBand
      71             : {
      72             :     int nBits;
      73             : 
      74             :     CPL_DISALLOW_COPY_ASSIGN(GenBinBitRasterBand)
      75             : 
      76             :   public:
      77             :     GenBinBitRasterBand(GenBinDataset *poDS, int nBits);
      78             : 
      79           0 :     ~GenBinBitRasterBand() override
      80           0 :     {
      81           0 :     }
      82             : 
      83             :     CPLErr IReadBlock(int, int, void *) override;
      84             : };
      85             : 
      86             : /************************************************************************/
      87             : /*                        GenBinBitRasterBand()                         */
      88             : /************************************************************************/
      89             : 
      90           0 : GenBinBitRasterBand::GenBinBitRasterBand(GenBinDataset *poDSIn, int nBitsIn)
      91           0 :     : nBits(nBitsIn)
      92             : {
      93           0 :     SetMetadataItem("NBITS", CPLString().Printf("%d", nBitsIn),
      94             :                     "IMAGE_STRUCTURE");
      95             : 
      96           0 :     poDS = poDSIn;
      97           0 :     nBand = 1;
      98             : 
      99           0 :     eDataType = GDT_Byte;
     100             : 
     101           0 :     nBlockXSize = poDSIn->nRasterXSize;
     102           0 :     nBlockYSize = 1;
     103           0 : }
     104             : 
     105             : /************************************************************************/
     106             : /*                             IReadBlock()                             */
     107             : /************************************************************************/
     108             : 
     109           0 : CPLErr GenBinBitRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff,
     110             :                                        void *pImage)
     111             : 
     112             : {
     113           0 :     GenBinDataset *poGDS = reinterpret_cast<GenBinDataset *>(poDS);
     114             : 
     115             :     /* -------------------------------------------------------------------- */
     116             :     /*      Establish desired position.                                     */
     117             :     /* -------------------------------------------------------------------- */
     118           0 :     const vsi_l_offset nLineStart =
     119           0 :         (static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBits) / 8;
     120           0 :     int iBitOffset = static_cast<int>(
     121           0 :         (static_cast<vsi_l_offset>(nBlockXSize) * nBlockYOff * nBits) % 8);
     122           0 :     const unsigned int nLineBytes = static_cast<unsigned int>(
     123           0 :         (static_cast<vsi_l_offset>(nBlockXSize) * (nBlockYOff + 1) * nBits +
     124           0 :          7) /
     125           0 :             8 -
     126             :         nLineStart);
     127             : 
     128             :     /* -------------------------------------------------------------------- */
     129             :     /*      Read data into buffer.                                          */
     130             :     /* -------------------------------------------------------------------- */
     131           0 :     GByte *pabyBuffer = static_cast<GByte *>(CPLCalloc(nLineBytes, 1));
     132             : 
     133           0 :     if (VSIFSeekL(poGDS->fpImage, nLineStart, SEEK_SET) != 0 ||
     134           0 :         VSIFReadL(pabyBuffer, 1, nLineBytes, poGDS->fpImage) != nLineBytes)
     135             :     {
     136           0 :         CPLError(CE_Failure, CPLE_FileIO,
     137             :                  "Failed to read %u bytes at offset %lu.\n%s", nLineBytes,
     138           0 :                  static_cast<unsigned long>(nLineStart), VSIStrerror(errno));
     139           0 :         CPLFree(pabyBuffer);
     140           0 :         return CE_Failure;
     141             :     }
     142             : 
     143             :     /* -------------------------------------------------------------------- */
     144             :     /*      Copy data, promoting to 8bit.                                   */
     145             :     /* -------------------------------------------------------------------- */
     146           0 :     GByte *pafImage = reinterpret_cast<GByte *>(pImage);
     147           0 :     if (nBits == 1)
     148             :     {
     149           0 :         for (int iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits)
     150             :         {
     151           0 :             if (pabyBuffer[iBitOffset >> 3] & (0x80 >> (iBitOffset & 7)))
     152           0 :                 pafImage[iX] = 1;
     153             :             else
     154           0 :                 pafImage[iX] = 0;
     155             :         }
     156             :     }
     157           0 :     else if (nBits == 2)
     158             :     {
     159           0 :         for (int iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits)
     160             :         {
     161           0 :             pafImage[iX] =
     162           0 :                 (pabyBuffer[iBitOffset >> 3]) >> (6 - (iBitOffset & 0x7)) & 0x3;
     163             :         }
     164             :     }
     165           0 :     else if (nBits == 4)
     166             :     {
     167           0 :         for (int iX = 0; iX < nBlockXSize; iX++, iBitOffset += nBits)
     168             :         {
     169           0 :             if (iBitOffset == 0)
     170           0 :                 pafImage[iX] = (pabyBuffer[iBitOffset >> 3]) >> 4;
     171             :             else
     172           0 :                 pafImage[iX] = (pabyBuffer[iBitOffset >> 3]) & 0xf;
     173             :         }
     174             :     }
     175             :     else
     176             :     {
     177           0 :         CPLAssert(false);
     178             :     }
     179             : 
     180           0 :     CPLFree(pabyBuffer);
     181             : 
     182           0 :     return CE_None;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /* ==================================================================== */
     187             : /*                              GenBinDataset                           */
     188             : /* ==================================================================== */
     189             : /************************************************************************/
     190             : 
     191             : /************************************************************************/
     192             : /*                            GenBinDataset()                             */
     193             : /************************************************************************/
     194             : 
     195           2 : GenBinDataset::GenBinDataset()
     196           2 :     : fpImage(nullptr), bGotTransform(false), papszHDR(nullptr)
     197             : {
     198           2 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     199           2 :     adfGeoTransform[0] = 0.0;
     200           2 :     adfGeoTransform[1] = 1.0;
     201           2 :     adfGeoTransform[2] = 0.0;
     202           2 :     adfGeoTransform[3] = 0.0;
     203           2 :     adfGeoTransform[4] = 0.0;
     204           2 :     adfGeoTransform[5] = 1.0;
     205           2 : }
     206             : 
     207             : /************************************************************************/
     208             : /*                            ~GenBinDataset()                          */
     209             : /************************************************************************/
     210             : 
     211           4 : GenBinDataset::~GenBinDataset()
     212             : 
     213             : {
     214           2 :     GenBinDataset::Close();
     215           4 : }
     216             : 
     217             : /************************************************************************/
     218             : /*                              Close()                                 */
     219             : /************************************************************************/
     220             : 
     221           4 : CPLErr GenBinDataset::Close()
     222             : {
     223           4 :     CPLErr eErr = CE_None;
     224           4 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     225             :     {
     226           2 :         if (GenBinDataset::FlushCache(true) != CE_None)
     227           0 :             eErr = CE_Failure;
     228             : 
     229           2 :         if (fpImage)
     230             :         {
     231           2 :             if (VSIFCloseL(fpImage) != 0)
     232             :             {
     233           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     234           0 :                 eErr = CE_Failure;
     235             :             }
     236             :         }
     237             : 
     238           2 :         CSLDestroy(papszHDR);
     239             : 
     240           2 :         if (GDALPamDataset::Close() != CE_None)
     241           0 :             eErr = CE_Failure;
     242             :     }
     243           4 :     return eErr;
     244             : }
     245             : 
     246             : /************************************************************************/
     247             : /*                          GetGeoTransform()                           */
     248             : /************************************************************************/
     249             : 
     250           1 : CPLErr GenBinDataset::GetGeoTransform(double *padfTransform)
     251             : 
     252             : {
     253           1 :     if (bGotTransform)
     254             :     {
     255           1 :         memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     256           1 :         return CE_None;
     257             :     }
     258             : 
     259           0 :     return GDALPamDataset::GetGeoTransform(padfTransform);
     260             : }
     261             : 
     262             : /************************************************************************/
     263             : /*                            GetFileList()                             */
     264             : /************************************************************************/
     265             : 
     266           1 : char **GenBinDataset::GetFileList()
     267             : 
     268             : {
     269           2 :     const CPLString osPath = CPLGetPathSafe(GetDescription());
     270           2 :     const CPLString osName = CPLGetBasenameSafe(GetDescription());
     271             : 
     272             :     // Main data file, etc.
     273           1 :     char **papszFileList = GDALPamDataset::GetFileList();
     274             : 
     275             :     // Header file.
     276           1 :     const CPLString osFilename = CPLFormCIFilenameSafe(osPath, osName, "hdr");
     277           1 :     papszFileList = CSLAddString(papszFileList, osFilename);
     278             : 
     279           2 :     return papszFileList;
     280             : }
     281             : 
     282             : /************************************************************************/
     283             : /*                       ParseCoordinateSystem()                        */
     284             : /************************************************************************/
     285             : 
     286           2 : void GenBinDataset::ParseCoordinateSystem(char **papszHdr)
     287             : 
     288             : {
     289           2 :     const char *pszProjName = CSLFetchNameValue(papszHdr, "PROJECTION_NAME");
     290           2 :     if (pszProjName == nullptr)
     291           0 :         return;
     292             : 
     293             :     /* -------------------------------------------------------------------- */
     294             :     /*      Translate zone and parameters into numeric form.                */
     295             :     /* -------------------------------------------------------------------- */
     296           2 :     int nZone = 0;
     297           2 :     if (const char *pszProjectionZone =
     298           2 :             CSLFetchNameValue(papszHdr, "PROJECTION_ZONE"))
     299           2 :         nZone = atoi(pszProjectionZone);
     300             : 
     301             : #if 0
     302             :     // TODO(schwehr): Why was this being done but not used?
     303             :     double adfProjParams[15] = { 0.0 };
     304             :     if( CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) )
     305             :     {
     306             :         char **papszTokens = CSLTokenizeString(
     307             :             CSLFetchNameValue( papszHdr, "PROJECTION_PARAMETERS" ) );
     308             : 
     309             :         for( int i = 0; i < 15 && papszTokens[i] != NULL; i++ )
     310             :             adfProjParams[i] = CPLAtofM( papszTokens[i] );
     311             : 
     312             :         CSLDestroy( papszTokens );
     313             :     }
     314             : #endif
     315             : 
     316             :     /* -------------------------------------------------------------------- */
     317             :     /*      Handle projections.                                             */
     318             :     /* -------------------------------------------------------------------- */
     319           2 :     const char *pszDatumName = CSLFetchNameValue(papszHdr, "DATUM_NAME");
     320             : 
     321           2 :     if (EQUAL(pszProjName, "UTM") && nZone != 0 && nZone > INT_MIN)
     322             :     {
     323             :         // Just getting that the negative zone for southern hemisphere is used.
     324           0 :         m_oSRS.SetUTM(std::abs(nZone), nZone > 0);
     325             :     }
     326             : 
     327           2 :     else if (EQUAL(pszProjName, "State Plane") && nZone != 0 && nZone > INT_MIN)
     328             :     {
     329           2 :         const int nPairs = sizeof(anUsgsEsriZones) / (2 * sizeof(int));
     330             : 
     331         218 :         for (int i = 0; i < nPairs; i++)
     332             :         {
     333         218 :             if (anUsgsEsriZones[i * 2 + 1] == nZone)
     334             :             {
     335           2 :                 nZone = anUsgsEsriZones[i * 2];
     336           2 :                 break;
     337             :             }
     338             :         }
     339             : 
     340           2 :         const char *pszUnits = CSLFetchNameValueDef(papszHdr, "MAP_UNITS", "");
     341           2 :         double dfUnits = 0.0;
     342           2 :         if (EQUAL(pszUnits, "feet"))
     343           2 :             dfUnits = CPLAtofM(SRS_UL_US_FOOT_CONV);
     344           0 :         else if (STARTS_WITH_CI(pszUnits, "MET"))
     345           0 :             dfUnits = 1.0;
     346             :         else
     347           0 :             pszUnits = nullptr;
     348             : 
     349           2 :         m_oSRS.SetStatePlane(std::abs(nZone),
     350           4 :                              pszDatumName == nullptr ||
     351           2 :                                  !EQUAL(pszDatumName, "NAD27"),
     352             :                              pszUnits, dfUnits);
     353             :     }
     354             : 
     355             :     /* -------------------------------------------------------------------- */
     356             :     /*      Setup the geographic coordinate system.                         */
     357             :     /* -------------------------------------------------------------------- */
     358           2 :     if (m_oSRS.GetAttrNode("GEOGCS") == nullptr)
     359             :     {
     360             :         const char *pszSpheroidName =
     361           0 :             CSLFetchNameValue(papszHdr, "SPHEROID_NAME");
     362             :         const char *pszSemiMajor =
     363           0 :             CSLFetchNameValue(papszHdr, "SEMI_MAJOR_AXIS");
     364             :         const char *pszSemiMinor =
     365           0 :             CSLFetchNameValue(papszHdr, "SEMI_MINOR_AXIS");
     366           0 :         if (pszDatumName != nullptr &&
     367           0 :             m_oSRS.SetWellKnownGeogCS(pszDatumName) == OGRERR_NONE)
     368             :         {
     369             :             // good
     370             :         }
     371           0 :         else if (pszSpheroidName && pszSemiMajor && pszSemiMinor)
     372             :         {
     373           0 :             const double dfSemiMajor = CPLAtofM(pszSemiMajor);
     374           0 :             const double dfSemiMinor = CPLAtofM(pszSemiMinor);
     375             : 
     376           0 :             m_oSRS.SetGeogCS(pszSpheroidName, pszSpheroidName, pszSpheroidName,
     377             :                              dfSemiMajor,
     378           0 :                              (dfSemiMajor == 0.0 || dfSemiMajor == dfSemiMinor)
     379             :                                  ? 0.0
     380           0 :                                  : 1.0 / (1.0 - dfSemiMinor / dfSemiMajor));
     381             :         }
     382             :         else  // fallback default.
     383           0 :             m_oSRS.SetWellKnownGeogCS("WGS84");
     384             :     }
     385             : }
     386             : 
     387             : /************************************************************************/
     388             : /*                                Open()                                */
     389             : /************************************************************************/
     390             : 
     391       28263 : GDALDataset *GenBinDataset::Open(GDALOpenInfo *poOpenInfo)
     392             : 
     393             : {
     394             :     /* -------------------------------------------------------------------- */
     395             :     /*      We assume the user is pointing to the binary (i.e. .bil) file.  */
     396             :     /* -------------------------------------------------------------------- */
     397       28263 :     if (poOpenInfo->nHeaderBytes < 2 || poOpenInfo->fpL == nullptr)
     398       26865 :         return nullptr;
     399             : 
     400             :     /* -------------------------------------------------------------------- */
     401             :     /*      Now we need to tear apart the filename to form a .HDR           */
     402             :     /*      filename.                                                       */
     403             :     /* -------------------------------------------------------------------- */
     404        2796 :     const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename);
     405        2796 :     const CPLString osName = CPLGetBasenameSafe(poOpenInfo->pszFilename);
     406        2796 :     CPLString osHDRFilename;
     407             : 
     408        1398 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     409        1398 :     if (papszSiblingFiles)
     410             :     {
     411             :         const int iFile =
     412        1392 :             CSLFindString(papszSiblingFiles,
     413        2784 :                           CPLFormFilenameSafe(nullptr, osName, "hdr").c_str());
     414        1392 :         if (iFile < 0)  // return if there is no corresponding .hdr file
     415        1150 :             return nullptr;
     416             : 
     417             :         osHDRFilename =
     418         242 :             CPLFormFilenameSafe(osPath, papszSiblingFiles[iFile], nullptr);
     419             :     }
     420             :     else
     421             :     {
     422           6 :         osHDRFilename = CPLFormCIFilenameSafe(osPath, osName, "hdr");
     423             :     }
     424             : 
     425         248 :     const bool bSelectedHDR = EQUAL(osHDRFilename, poOpenInfo->pszFilename);
     426             : 
     427             :     /* -------------------------------------------------------------------- */
     428             :     /*      Do we have a .hdr file?                                         */
     429             :     /* -------------------------------------------------------------------- */
     430         248 :     VSILFILE *fp = VSIFOpenL(osHDRFilename, "r");
     431         248 :     if (fp == nullptr)
     432             :     {
     433           5 :         return nullptr;
     434             :     }
     435             : 
     436             :     /* -------------------------------------------------------------------- */
     437             :     /*      Read a chunk to skim for expected keywords.                     */
     438             :     /* -------------------------------------------------------------------- */
     439         243 :     char achHeader[1000] = {'\0'};
     440             : 
     441             :     const int nRead =
     442         243 :         static_cast<int>(VSIFReadL(achHeader, 1, sizeof(achHeader) - 1, fp));
     443         243 :     achHeader[nRead] = '\0';
     444         243 :     CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
     445             : 
     446         243 :     if (strstr(achHeader, "BANDS:") == nullptr ||
     447           2 :         strstr(achHeader, "ROWS:") == nullptr ||
     448           2 :         strstr(achHeader, "COLS:") == nullptr)
     449             :     {
     450         241 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     451         241 :         return nullptr;
     452             :     }
     453             : 
     454             :     /* -------------------------------------------------------------------- */
     455             :     /*      Has the user selected the .hdr file to open?                    */
     456             :     /* -------------------------------------------------------------------- */
     457           2 :     if (bSelectedHDR)
     458             :     {
     459           0 :         CPLError(
     460             :             CE_Failure, CPLE_AppDefined,
     461             :             "The selected file is an Generic Binary header file, but to "
     462             :             "open Generic Binary datasets, the data file should be selected "
     463             :             "instead of the .hdr file.  Please try again selecting"
     464             :             "the raw data file corresponding to the header file: %s",
     465             :             poOpenInfo->pszFilename);
     466           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     467           0 :         return nullptr;
     468             :     }
     469             : 
     470             :     /* -------------------------------------------------------------------- */
     471             :     /*      Read the .hdr file.                                             */
     472             :     /* -------------------------------------------------------------------- */
     473           2 :     char **papszHdr = nullptr;
     474           2 :     const char *pszLine = CPLReadLineL(fp);
     475             : 
     476          46 :     while (pszLine != nullptr)
     477             :     {
     478          44 :         if (EQUAL(pszLine, "PROJECTION_PARAMETERS:"))
     479             :         {
     480           2 :             CPLString osPP = pszLine;
     481             : 
     482           2 :             pszLine = CPLReadLineL(fp);
     483          32 :             while (pszLine != nullptr && (*pszLine == '\t' || *pszLine == ' '))
     484             :             {
     485          30 :                 osPP += pszLine;
     486          30 :                 pszLine = CPLReadLineL(fp);
     487             :             }
     488           2 :             papszHdr = CSLAddString(papszHdr, osPP);
     489             :         }
     490             :         else
     491             :         {
     492          42 :             char *pszName = nullptr;
     493          42 :             const char *pszKey = CPLParseNameValue(pszLine, &pszName);
     494          42 :             if (pszKey && pszName)
     495             :             {
     496          42 :                 CPLString osValue = pszKey;
     497          42 :                 osValue.Trim();
     498             : 
     499          42 :                 papszHdr = CSLSetNameValue(papszHdr, pszName, osValue);
     500             :             }
     501          42 :             CPLFree(pszName);
     502             : 
     503          42 :             pszLine = CPLReadLineL(fp);
     504             :         }
     505             :     }
     506             : 
     507           2 :     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     508             : 
     509           2 :     if (CSLFetchNameValue(papszHdr, "COLS") == nullptr ||
     510           4 :         CSLFetchNameValue(papszHdr, "ROWS") == nullptr ||
     511           2 :         CSLFetchNameValue(papszHdr, "BANDS") == nullptr)
     512             :     {
     513           0 :         CSLDestroy(papszHdr);
     514           0 :         return nullptr;
     515             :     }
     516             : 
     517             :     /* -------------------------------------------------------------------- */
     518             :     /*      Create a corresponding GDALDataset.                             */
     519             :     /* -------------------------------------------------------------------- */
     520           4 :     auto poDS = std::make_unique<GenBinDataset>();
     521             : 
     522             :     /* -------------------------------------------------------------------- */
     523             :     /*      Capture some information from the file that is of interest.     */
     524             :     /* -------------------------------------------------------------------- */
     525           2 :     const int nBands = atoi(CSLFetchNameValue(papszHdr, "BANDS"));
     526             : 
     527           2 :     poDS->nRasterXSize = atoi(CSLFetchNameValue(papszHdr, "COLS"));
     528           2 :     poDS->nRasterYSize = atoi(CSLFetchNameValue(papszHdr, "ROWS"));
     529           2 :     poDS->papszHDR = papszHdr;
     530             : 
     531           4 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     532           2 :         !GDALCheckBandCount(nBands, FALSE))
     533             :     {
     534           0 :         return nullptr;
     535             :     }
     536             : 
     537           2 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
     538           2 :     poDS->eAccess = poOpenInfo->eAccess;
     539             : 
     540             :     /* -------------------------------------------------------------------- */
     541             :     /*      Figure out the data type.                                       */
     542             :     /* -------------------------------------------------------------------- */
     543           2 :     const char *pszDataType = CSLFetchNameValue(papszHdr, "DATATYPE");
     544           2 :     GDALDataType eDataType = GDT_Byte;
     545           2 :     int nBits = -1;  // Only needed for partial byte types
     546             : 
     547           2 :     if (pszDataType == nullptr)
     548             :     {
     549             :         // nothing to do
     550             :     }
     551           2 :     else if (EQUAL(pszDataType, "U16"))
     552           0 :         eDataType = GDT_UInt16;
     553           2 :     else if (EQUAL(pszDataType, "S16"))
     554           0 :         eDataType = GDT_Int16;
     555           2 :     else if (EQUAL(pszDataType, "F32"))
     556           0 :         eDataType = GDT_Float32;
     557           2 :     else if (EQUAL(pszDataType, "F64"))
     558           0 :         eDataType = GDT_Float64;
     559           2 :     else if (EQUAL(pszDataType, "U8"))
     560             :     {
     561             :         // nothing to do
     562             :     }
     563           0 :     else if (EQUAL(pszDataType, "U1") || EQUAL(pszDataType, "U2") ||
     564           0 :              EQUAL(pszDataType, "U4"))
     565             :     {
     566           0 :         nBits = atoi(pszDataType + 1);
     567           0 :         if (nBands != 1)
     568             :         {
     569           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     570             :                      "Only one band is supported for U1/U2/U4 data type");
     571           0 :             return nullptr;
     572             :         }
     573             :     }
     574             :     else
     575             :     {
     576           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     577             :                  "DATATYPE=%s not recognised, assuming Byte.", pszDataType);
     578             :     }
     579             : 
     580             :     /* -------------------------------------------------------------------- */
     581             :     /*      Do we need byte swapping?                                       */
     582             :     /* -------------------------------------------------------------------- */
     583             : 
     584           2 :     RawRasterBand::ByteOrder eByteOrder = RawRasterBand::NATIVE_BYTE_ORDER;
     585             : 
     586           2 :     const char *pszByteOrder = CSLFetchNameValue(papszHdr, "BYTE_ORDER");
     587           2 :     if (pszByteOrder)
     588             :     {
     589           2 :         eByteOrder = EQUAL(pszByteOrder, "LSB")
     590           2 :                          ? RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN
     591             :                          : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN;
     592             :     }
     593             : 
     594             :     /* -------------------------------------------------------------------- */
     595             :     /*      Work out interleaving info.                                     */
     596             :     /* -------------------------------------------------------------------- */
     597           2 :     const int nItemSize = GDALGetDataTypeSizeBytes(eDataType);
     598           2 :     int nPixelOffset = 0;
     599           2 :     int nLineOffset = 0;
     600           2 :     vsi_l_offset nBandOffset = 0;
     601           2 :     bool bIntOverflow = false;
     602             : 
     603           2 :     const char *pszInterleaving = CSLFetchNameValue(papszHdr, "INTERLEAVING");
     604           2 :     if (pszInterleaving == nullptr)
     605           0 :         pszInterleaving = "BIL";
     606             : 
     607           2 :     if (EQUAL(pszInterleaving, "BSQ") || EQUAL(pszInterleaving, "NA"))
     608             :     {
     609           2 :         nPixelOffset = nItemSize;
     610           2 :         if (nItemSize <= 0 || poDS->nRasterXSize > INT_MAX / nItemSize)
     611           0 :             bIntOverflow = true;
     612             :         else
     613             :         {
     614           2 :             nLineOffset = nItemSize * poDS->nRasterXSize;
     615           2 :             nBandOffset =
     616           2 :                 nLineOffset * static_cast<vsi_l_offset>(poDS->nRasterYSize);
     617             :         }
     618             :     }
     619           0 :     else if (EQUAL(pszInterleaving, "BIP"))
     620             :     {
     621           0 :         nPixelOffset = nItemSize * nBands;
     622           0 :         if (nPixelOffset == 0 || poDS->nRasterXSize > INT_MAX / nPixelOffset)
     623           0 :             bIntOverflow = true;
     624             :         else
     625             :         {
     626           0 :             nLineOffset = nPixelOffset * poDS->nRasterXSize;
     627           0 :             nBandOffset = nItemSize;
     628             :         }
     629             :     }
     630             :     else
     631             :     {
     632           0 :         if (!EQUAL(pszInterleaving, "BIL"))
     633           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     634             :                      "INTERLEAVING:%s not recognised, assume BIL.",
     635             :                      pszInterleaving);
     636             : 
     637           0 :         nPixelOffset = nItemSize;
     638           0 :         if (nPixelOffset == 0 || nBands == 0 ||
     639           0 :             poDS->nRasterXSize > INT_MAX / (nPixelOffset * nBands))
     640           0 :             bIntOverflow = true;
     641             :         else
     642             :         {
     643           0 :             nLineOffset = nPixelOffset * nBands * poDS->nRasterXSize;
     644           0 :             nBandOffset =
     645           0 :                 nItemSize * static_cast<vsi_l_offset>(poDS->nRasterXSize);
     646             :         }
     647             :     }
     648             : 
     649           2 :     if (bIntOverflow)
     650             :     {
     651           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Int overflow occurred.");
     652           0 :         return nullptr;
     653             :     }
     654             : 
     655           4 :     if (nBits < 0 &&
     656           2 :         !RAWDatasetCheckMemoryUsage(poDS->nRasterXSize, poDS->nRasterYSize,
     657             :                                     nBands, nItemSize, nPixelOffset,
     658           2 :                                     nLineOffset, 0, nBandOffset, poDS->fpImage))
     659             :     {
     660           0 :         return nullptr;
     661             :     }
     662             : 
     663           2 :     poDS->SetDescription(poOpenInfo->pszFilename);
     664           2 :     poDS->PamInitialize();
     665             : 
     666             :     /* -------------------------------------------------------------------- */
     667             :     /*      Create band information objects.                                */
     668             :     /* -------------------------------------------------------------------- */
     669          16 :     for (int i = 0; i < nBands; i++)
     670             :     {
     671          14 :         if (nBits != -1)
     672             :         {
     673           0 :             poDS->SetBand(i + 1, new GenBinBitRasterBand(poDS.get(), nBits));
     674             :         }
     675             :         else
     676             :         {
     677             :             auto poBand = RawRasterBand::Create(
     678          28 :                 poDS.get(), i + 1, poDS->fpImage, nBandOffset * i, nPixelOffset,
     679          14 :                 nLineOffset, eDataType, eByteOrder, RawRasterBand::OwnFP::NO);
     680          14 :             if (!poBand)
     681           0 :                 return nullptr;
     682          14 :             poDS->SetBand(i + 1, std::move(poBand));
     683             :         }
     684             :     }
     685             : 
     686             :     /* -------------------------------------------------------------------- */
     687             :     /*      Get geotransform.                                               */
     688             :     /* -------------------------------------------------------------------- */
     689           4 :     if (poDS->nRasterXSize > 1 && poDS->nRasterYSize > 1 &&
     690           2 :         CSLFetchNameValue(papszHdr, "UL_X_COORDINATE") != nullptr &&
     691           2 :         CSLFetchNameValue(papszHdr, "UL_Y_COORDINATE") != nullptr &&
     692           6 :         CSLFetchNameValue(papszHdr, "LR_X_COORDINATE") != nullptr &&
     693           2 :         CSLFetchNameValue(papszHdr, "LR_Y_COORDINATE") != nullptr)
     694             :     {
     695             :         const double dfULX =
     696           2 :             CPLAtofM(CSLFetchNameValue(papszHdr, "UL_X_COORDINATE"));
     697             :         const double dfULY =
     698           2 :             CPLAtofM(CSLFetchNameValue(papszHdr, "UL_Y_COORDINATE"));
     699             :         const double dfLRX =
     700           2 :             CPLAtofM(CSLFetchNameValue(papszHdr, "LR_X_COORDINATE"));
     701             :         const double dfLRY =
     702           2 :             CPLAtofM(CSLFetchNameValue(papszHdr, "LR_Y_COORDINATE"));
     703             : 
     704           2 :         poDS->adfGeoTransform[1] = (dfLRX - dfULX) / (poDS->nRasterXSize - 1);
     705           2 :         poDS->adfGeoTransform[2] = 0.0;
     706           2 :         poDS->adfGeoTransform[4] = 0.0;
     707           2 :         poDS->adfGeoTransform[5] = (dfLRY - dfULY) / (poDS->nRasterYSize - 1);
     708             : 
     709           2 :         poDS->adfGeoTransform[0] = dfULX - poDS->adfGeoTransform[1] * 0.5;
     710           2 :         poDS->adfGeoTransform[3] = dfULY - poDS->adfGeoTransform[5] * 0.5;
     711             : 
     712           2 :         poDS->bGotTransform = true;
     713             :     }
     714             : 
     715             :     /* -------------------------------------------------------------------- */
     716             :     /*      Try and parse the coordinate system.                            */
     717             :     /* -------------------------------------------------------------------- */
     718           2 :     poDS->ParseCoordinateSystem(papszHdr);
     719             : 
     720             :     /* -------------------------------------------------------------------- */
     721             :     /*      Initialize any PAM information.                                 */
     722             :     /* -------------------------------------------------------------------- */
     723           2 :     poDS->TryLoadXML();
     724             : 
     725             :     /* -------------------------------------------------------------------- */
     726             :     /*      Check for overviews.                                            */
     727             :     /* -------------------------------------------------------------------- */
     728           2 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     729             : 
     730           2 :     return poDS.release();
     731             : }
     732             : 
     733             : /************************************************************************/
     734             : /*                         GDALRegister_GenBin()                        */
     735             : /************************************************************************/
     736             : 
     737        1682 : void GDALRegister_GenBin()
     738             : 
     739             : {
     740        1682 :     if (GDALGetDriverByName("GenBin") != nullptr)
     741         301 :         return;
     742             : 
     743        1381 :     GDALDriver *poDriver = new GDALDriver();
     744             : 
     745        1381 :     poDriver->SetDescription("GenBin");
     746        1381 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     747        1381 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     748        1381 :                               "Generic Binary (.hdr Labelled)");
     749        1381 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/genbin.html");
     750        1381 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     751             : 
     752        1381 :     poDriver->pfnOpen = GenBinDataset::Open;
     753             : 
     754        1381 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     755             : }

Generated by: LCOV version 1.14