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

Generated by: LCOV version 1.14