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

Generated by: LCOV version 1.14