LCOV - code coverage report
Current view: top level - frmts/raw - genbindataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 187 295 63.4 %
Date: 2024-11-21 22:18:42 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 = CPLGetPath(GetDescription());
     270           2 :     const CPLString osName = CPLGetBasename(GetDescription());
     271             : 
     272             :     // Main data file, etc.
     273           1 :     char **papszFileList = GDALPamDataset::GetFileList();
     274             : 
     275             :     // Header file.
     276           1 :     const CPLString osFilename = CPLFormCIFilename(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       27999 : GDALDataset *GenBinDataset::Open(GDALOpenInfo *poOpenInfo)
     392             : 
     393             : {
     394             :     /* -------------------------------------------------------------------- */
     395             :     /*      We assume the user is pointing to the binary (i.e. .bil) file.  */
     396             :     /* -------------------------------------------------------------------- */
     397       27999 :     if (poOpenInfo->nHeaderBytes < 2 || poOpenInfo->fpL == nullptr)
     398       26603 :         return nullptr;
     399             : 
     400             :     /* -------------------------------------------------------------------- */
     401             :     /*      Now we need to tear apart the filename to form a .HDR           */
     402             :     /*      filename.                                                       */
     403             :     /* -------------------------------------------------------------------- */
     404        2792 :     const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
     405        2792 :     const CPLString osName = CPLGetBasename(poOpenInfo->pszFilename);
     406        2792 :     CPLString osHDRFilename;
     407             : 
     408        1396 :     char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
     409        1396 :     if (papszSiblingFiles)
     410             :     {
     411        1390 :         const int iFile = CSLFindString(
     412             :             papszSiblingFiles, CPLFormFilename(nullptr, osName, "hdr"));
     413        1390 :         if (iFile < 0)  // return if there is no corresponding .hdr file
     414        1148 :             return nullptr;
     415             : 
     416             :         osHDRFilename =
     417         242 :             CPLFormFilename(osPath, papszSiblingFiles[iFile], nullptr);
     418             :     }
     419             :     else
     420             :     {
     421           6 :         osHDRFilename = CPLFormCIFilename(osPath, osName, "hdr");
     422             :     }
     423             : 
     424         248 :     const bool bSelectedHDR = EQUAL(osHDRFilename, poOpenInfo->pszFilename);
     425             : 
     426             :     /* -------------------------------------------------------------------- */
     427             :     /*      Do we have a .hdr file?                                         */
     428             :     /* -------------------------------------------------------------------- */
     429         248 :     VSILFILE *fp = VSIFOpenL(osHDRFilename, "r");
     430         248 :     if (fp == nullptr)
     431             :     {
     432           5 :         return nullptr;
     433             :     }
     434             : 
     435             :     /* -------------------------------------------------------------------- */
     436             :     /*      Read a chunk to skim for expected keywords.                     */
     437             :     /* -------------------------------------------------------------------- */
     438         243 :     char achHeader[1000] = {'\0'};
     439             : 
     440             :     const int nRead =
     441         243 :         static_cast<int>(VSIFReadL(achHeader, 1, sizeof(achHeader) - 1, fp));
     442         243 :     achHeader[nRead] = '\0';
     443         243 :     CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET));
     444             : 
     445         243 :     if (strstr(achHeader, "BANDS:") == nullptr ||
     446           2 :         strstr(achHeader, "ROWS:") == nullptr ||
     447           2 :         strstr(achHeader, "COLS:") == nullptr)
     448             :     {
     449         241 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     450         241 :         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->adfGeoTransform[1] = (dfLRX - dfULX) / (poDS->nRasterXSize - 1);
     704           2 :         poDS->adfGeoTransform[2] = 0.0;
     705           2 :         poDS->adfGeoTransform[4] = 0.0;
     706           2 :         poDS->adfGeoTransform[5] = (dfLRY - dfULY) / (poDS->nRasterYSize - 1);
     707             : 
     708           2 :         poDS->adfGeoTransform[0] = dfULX - poDS->adfGeoTransform[1] * 0.5;
     709           2 :         poDS->adfGeoTransform[3] = dfULY - poDS->adfGeoTransform[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        1595 : void GDALRegister_GenBin()
     737             : 
     738             : {
     739        1595 :     if (GDALGetDriverByName("GenBin") != nullptr)
     740         302 :         return;
     741             : 
     742        1293 :     GDALDriver *poDriver = new GDALDriver();
     743             : 
     744        1293 :     poDriver->SetDescription("GenBin");
     745        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     746        1293 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     747        1293 :                               "Generic Binary (.hdr Labelled)");
     748        1293 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/genbin.html");
     749        1293 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     750             : 
     751        1293 :     poDriver->pfnOpen = GenBinDataset::Open;
     752             : 
     753        1293 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     754             : }

Generated by: LCOV version 1.14