LCOV - code coverage report
Current view: top level - frmts/raw - byndataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 160 244 65.6 %
Date: 2025-03-28 21:34:50 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Natural Resources Canada's Geoid BYN file format
       4             :  * Purpose:  Implementation of BYN format
       5             :  * Author:   Ivan Lucena, ivan.lucena@outlook.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2018, Ivan Lucena
       9             :  * Copyright (c) 2018, Even Rouault
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "byndataset.h"
      16             : #include "rawdataset.h"
      17             : 
      18             : #include "cpl_string.h"
      19             : #include "gdal_frmts.h"
      20             : #include "ogr_spatialref.h"
      21             : #include "ogr_srs_api.h"
      22             : 
      23             : #include <algorithm>
      24             : #include <cstdlib>
      25             : #include <limits>
      26             : 
      27             : // Specification at
      28             : // https://www.nrcan.gc.ca/sites/www.nrcan.gc.ca/files/earthsciences/pdf/gpshgrid_e.pdf
      29             : 
      30             : const static BYNEllipsoids EllipsoidTable[] = {
      31             :     {"GRS80", 6378137.0, 298.257222101},
      32             :     {"WGS84", 6378137.0, 298.257223564},
      33             :     {"ALT1", 6378136.3, 298.256415099},
      34             :     {"GRS67", 6378160.0, 298.247167427},
      35             :     {"ELLIP1", 6378136.46, 298.256415099},
      36             :     {"ALT2", 6378136.3, 298.257},
      37             :     {"ELLIP2", 6378136.0, 298.257},
      38             :     {"CLARKE 1866", 6378206.4, 294.9786982}};
      39             : 
      40             : /************************************************************************/
      41             : /*                            BYNRasterBand()                           */
      42             : /************************************************************************/
      43             : 
      44           4 : BYNRasterBand::BYNRasterBand(GDALDataset *poDSIn, int nBandIn,
      45             :                              VSILFILE *fpRawIn, vsi_l_offset nImgOffsetIn,
      46             :                              int nPixelOffsetIn, int nLineOffsetIn,
      47           4 :                              GDALDataType eDataTypeIn, int bNativeOrderIn)
      48             :     : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn,
      49             :                     nLineOffsetIn, eDataTypeIn, bNativeOrderIn,
      50           4 :                     RawRasterBand::OwnFP::NO)
      51             : {
      52           4 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                           ~BYNRasterBand()                           */
      56             : /************************************************************************/
      57             : 
      58           8 : BYNRasterBand::~BYNRasterBand()
      59             : {
      60           8 : }
      61             : 
      62             : /************************************************************************/
      63             : /*                           GetNoDataValue()                           */
      64             : /************************************************************************/
      65             : 
      66           0 : double BYNRasterBand::GetNoDataValue(int *pbSuccess)
      67             : {
      68           0 :     if (pbSuccess)
      69           0 :         *pbSuccess = TRUE;
      70           0 :     int bSuccess = FALSE;
      71           0 :     double dfNoData = GDALPamRasterBand::GetNoDataValue(&bSuccess);
      72           0 :     if (bSuccess)
      73             :     {
      74           0 :         return dfNoData;
      75             :     }
      76           0 :     const double dfFactor =
      77           0 :         reinterpret_cast<BYNDataset *>(poDS)->hHeader.dfFactor;
      78           0 :     return eDataType == GDT_Int16 ? 32767.0 : 9999.0 * dfFactor;
      79             : }
      80             : 
      81             : /************************************************************************/
      82             : /*                              GetScale()                              */
      83             : /************************************************************************/
      84             : 
      85           0 : double BYNRasterBand::GetScale(int *pbSuccess)
      86             : {
      87           0 :     if (pbSuccess != nullptr)
      88           0 :         *pbSuccess = TRUE;
      89           0 :     const double dfFactor =
      90           0 :         reinterpret_cast<BYNDataset *>(poDS)->hHeader.dfFactor;
      91           0 :     return (dfFactor != 0.0) ? 1.0 / dfFactor : 0.0;
      92             : }
      93             : 
      94             : /************************************************************************/
      95             : /* ==================================================================== */
      96             : /*                              BYNDataset                              */
      97             : /* ==================================================================== */
      98             : /************************************************************************/
      99             : 
     100           4 : BYNDataset::BYNDataset()
     101             :     : fpImage(nullptr), hHeader{0, 0, 0, 0, 0, 0,   0,   0, 0.0, 0,   0, 0,
     102           4 :                                 0, 0, 0, 0, 0, 0.0, 0.0, 0, 0,   0.0, 0}
     103             : {
     104           4 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     105           4 :     adfGeoTransform[0] = 0.0;
     106           4 :     adfGeoTransform[1] = 1.0;
     107           4 :     adfGeoTransform[2] = 0.0;
     108           4 :     adfGeoTransform[3] = 0.0;
     109           4 :     adfGeoTransform[4] = 0.0;
     110           4 :     adfGeoTransform[5] = 1.0;
     111           4 : }
     112             : 
     113             : /************************************************************************/
     114             : /*                            ~BYNDataset()                             */
     115             : /************************************************************************/
     116             : 
     117           8 : BYNDataset::~BYNDataset()
     118             : 
     119             : {
     120           4 :     BYNDataset::Close();
     121           8 : }
     122             : 
     123             : /************************************************************************/
     124             : /*                              Close()                                 */
     125             : /************************************************************************/
     126             : 
     127           8 : CPLErr BYNDataset::Close()
     128             : {
     129           8 :     CPLErr eErr = CE_None;
     130           8 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     131             :     {
     132           4 :         if (BYNDataset::FlushCache(true) != CE_None)
     133           0 :             eErr = CE_Failure;
     134             : 
     135           4 :         if (fpImage != nullptr)
     136             :         {
     137           4 :             if (VSIFCloseL(fpImage) != 0)
     138             :             {
     139           0 :                 eErr = CE_Failure;
     140           0 :                 CPLError(CE_Failure, CPLE_FileIO, "I/O error");
     141             :             }
     142             :         }
     143             : 
     144           4 :         if (GDALPamDataset::Close() != CE_None)
     145           0 :             eErr = CE_Failure;
     146             :     }
     147           8 :     return eErr;
     148             : }
     149             : 
     150             : /************************************************************************/
     151             : /*                              Identify()                              */
     152             : /************************************************************************/
     153             : 
     154       49465 : int BYNDataset::Identify(GDALOpenInfo *poOpenInfo)
     155             : 
     156             : {
     157       49465 :     if (poOpenInfo->nHeaderBytes < BYN_HDR_SZ)
     158       46274 :         return FALSE;
     159             : 
     160             : /* -------------------------------------------------------------------- */
     161             : /*      Check file extension (.byn/.err)                                */
     162             : /* -------------------------------------------------------------------- */
     163             : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
     164        3191 :     const char *pszFileExtension = poOpenInfo->osExtension.c_str();
     165             : 
     166        3191 :     if (!EQUAL(pszFileExtension, "byn") && !EQUAL(pszFileExtension, "err"))
     167             :     {
     168        3183 :         return FALSE;
     169             :     }
     170             : #endif
     171             : 
     172             :     /* -------------------------------------------------------------------- */
     173             :     /*      Check some value's ranges on header                             */
     174             :     /* -------------------------------------------------------------------- */
     175             : 
     176           8 :     BYNHeader hHeader = {0, 0, 0, 0, 0, 0,   0,   0, 0.0, 0,   0, 0,
     177             :                          0, 0, 0, 0, 0, 0.0, 0.0, 0, 0,   0.0, 0};
     178             : 
     179           8 :     buffer2header(poOpenInfo->pabyHeader, &hHeader);
     180             : 
     181           8 :     if (hHeader.nGlobal < 0 || hHeader.nGlobal > 1 || hHeader.nType < 0 ||
     182           8 :         hHeader.nType > 9 || (hHeader.nSizeOf != 2 && hHeader.nSizeOf != 4) ||
     183           8 :         hHeader.nVDatum < 0 || hHeader.nVDatum > 3 || hHeader.nDescrip < 0 ||
     184           8 :         hHeader.nDescrip > 3 || hHeader.nSubType < 0 || hHeader.nSubType > 9 ||
     185           8 :         hHeader.nDatum < 0 || hHeader.nDatum > 1 || hHeader.nEllipsoid < 0 ||
     186           8 :         hHeader.nEllipsoid > 7 || hHeader.nByteOrder < 0 ||
     187           8 :         hHeader.nByteOrder > 1 || hHeader.nScale < 0 || hHeader.nScale > 1)
     188           0 :         return FALSE;
     189             : 
     190             : #if 0
     191             :     // We have disabled those checks as invalid values are often found in some
     192             :     // datasets, such as http://s3.microsurvey.com/os/fieldgenius/geoids/Lithuania.zip
     193             :     // We don't use those fields, so we may just ignore them.
     194             :     if((hHeader.nTideSys   < 0 || hHeader.nTideSys   > 2 ||
     195             :         hHeader.nPtType    < 0 || hHeader.nPtType    > 1 ))
     196             :     {
     197             :         // Some datasets use 0xCC as a marker for invalidity for
     198             :         // records starting from Geopotential Wo
     199             :         for( int i = 52; i < 78; i++ )
     200             :         {
     201             :             if( poOpenInfo->pabyHeader[i] != 0xCC )
     202             :                 return FALSE;
     203             :         }
     204             :     }
     205             : #endif
     206             : 
     207           8 :     if (hHeader.nScale == 0)
     208             :     {
     209          16 :         if ((std::abs(static_cast<GIntBig>(hHeader.nSouth) -
     210          16 :                       (hHeader.nDLat / 2)) > BYN_MAX_LAT) ||
     211           8 :             (std::abs(static_cast<GIntBig>(hHeader.nNorth) +
     212          16 :                       (hHeader.nDLat / 2)) > BYN_MAX_LAT) ||
     213           8 :             (std::abs(static_cast<GIntBig>(hHeader.nWest) -
     214          24 :                       (hHeader.nDLon / 2)) > BYN_MAX_LON) ||
     215           8 :             (std::abs(static_cast<GIntBig>(hHeader.nEast) +
     216           8 :                       (hHeader.nDLon / 2)) > BYN_MAX_LON))
     217           0 :             return FALSE;
     218             :     }
     219             :     else
     220             :     {
     221           0 :         if ((std::abs(static_cast<GIntBig>(hHeader.nSouth) -
     222           0 :                       (hHeader.nDLat / 2)) > BYN_MAX_LAT_SCL) ||
     223           0 :             (std::abs(static_cast<GIntBig>(hHeader.nNorth) +
     224           0 :                       (hHeader.nDLat / 2)) > BYN_MAX_LAT_SCL) ||
     225           0 :             (std::abs(static_cast<GIntBig>(hHeader.nWest) -
     226           0 :                       (hHeader.nDLon / 2)) > BYN_MAX_LON_SCL) ||
     227           0 :             (std::abs(static_cast<GIntBig>(hHeader.nEast) +
     228           0 :                       (hHeader.nDLon / 2)) > BYN_MAX_LON_SCL))
     229           0 :             return FALSE;
     230             :     }
     231             : 
     232           8 :     return TRUE;
     233             : }
     234             : 
     235             : /************************************************************************/
     236             : /*                                Open()                                */
     237             : /************************************************************************/
     238             : 
     239           4 : GDALDataset *BYNDataset::Open(GDALOpenInfo *poOpenInfo)
     240             : 
     241             : {
     242           8 :     if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr ||
     243           4 :         poOpenInfo->eAccess == GA_Update)
     244           0 :         return nullptr;
     245             : 
     246             :     /* -------------------------------------------------------------------- */
     247             :     /*      Create a corresponding GDALDataset.                             */
     248             :     /* -------------------------------------------------------------------- */
     249             : 
     250           8 :     auto poDS = std::make_unique<BYNDataset>();
     251             : 
     252           4 :     poDS->eAccess = poOpenInfo->eAccess;
     253           4 :     std::swap(poDS->fpImage, poOpenInfo->fpL);
     254             : 
     255             :     /* -------------------------------------------------------------------- */
     256             :     /*      Read the header.                                                */
     257             :     /* -------------------------------------------------------------------- */
     258             : 
     259           4 :     buffer2header(poOpenInfo->pabyHeader, &poDS->hHeader);
     260             : 
     261             :     /********************************/
     262             :     /* Scale boundaries and spacing */
     263             :     /********************************/
     264             : 
     265           4 :     double dfSouth = poDS->hHeader.nSouth;
     266           4 :     double dfNorth = poDS->hHeader.nNorth;
     267           4 :     double dfWest = poDS->hHeader.nWest;
     268           4 :     double dfEast = poDS->hHeader.nEast;
     269           4 :     double dfDLat = poDS->hHeader.nDLat;
     270           4 :     double dfDLon = poDS->hHeader.nDLon;
     271             : 
     272           4 :     if (poDS->hHeader.nScale == 1)
     273             :     {
     274           0 :         dfSouth *= BYN_SCALE;
     275           0 :         dfNorth *= BYN_SCALE;
     276           0 :         dfWest *= BYN_SCALE;
     277           0 :         dfEast *= BYN_SCALE;
     278           0 :         dfDLat *= BYN_SCALE;
     279           0 :         dfDLon *= BYN_SCALE;
     280             :     }
     281             : 
     282             :     /******************************/
     283             :     /* Calculate rows and columns */
     284             :     /******************************/
     285             : 
     286           4 :     double dfXSize = -1;
     287           4 :     double dfYSize = -1;
     288             : 
     289           4 :     poDS->nRasterXSize = -1;
     290           4 :     poDS->nRasterYSize = -1;
     291             : 
     292           4 :     if (dfDLat != 0.0 && dfDLon != 0.0)
     293             :     {
     294           4 :         dfXSize = ((dfEast - dfWest + 1.0) / dfDLon) + 1.0;
     295           4 :         dfYSize = ((dfNorth - dfSouth + 1.0) / dfDLat) + 1.0;
     296             :     }
     297             : 
     298           4 :     if (dfXSize > 0.0 && dfXSize < std::numeric_limits<double>::max() &&
     299           8 :         dfYSize > 0.0 && dfYSize < std::numeric_limits<double>::max())
     300             :     {
     301           4 :         poDS->nRasterXSize = static_cast<GInt32>(dfXSize);
     302           4 :         poDS->nRasterYSize = static_cast<GInt32>(dfYSize);
     303             :     }
     304             : 
     305           4 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     306             :     {
     307           0 :         return nullptr;
     308             :     }
     309             : 
     310             :     /*****************************/
     311             :     /* Build GeoTransform matrix */
     312             :     /*****************************/
     313             : 
     314           4 :     poDS->adfGeoTransform[0] = (dfWest - (dfDLon / 2.0)) / 3600.0;
     315           4 :     poDS->adfGeoTransform[1] = dfDLon / 3600.0;
     316           4 :     poDS->adfGeoTransform[2] = 0.0;
     317           4 :     poDS->adfGeoTransform[3] = (dfNorth + (dfDLat / 2.0)) / 3600.0;
     318           4 :     poDS->adfGeoTransform[4] = 0.0;
     319           4 :     poDS->adfGeoTransform[5] = -1 * dfDLat / 3600.0;
     320             : 
     321             :     /*********************/
     322             :     /* Set data type     */
     323             :     /*********************/
     324             : 
     325           4 :     GDALDataType eDT = GDT_Unknown;
     326             : 
     327           4 :     if (poDS->hHeader.nSizeOf == 2)
     328           0 :         eDT = GDT_Int16;
     329           4 :     else if (poDS->hHeader.nSizeOf == 4)
     330           4 :         eDT = GDT_Int32;
     331             :     else
     332             :     {
     333           0 :         return nullptr;
     334             :     }
     335             : 
     336             :     /* -------------------------------------------------------------------- */
     337             :     /*      Create band information object.                                 */
     338             :     /* -------------------------------------------------------------------- */
     339             : 
     340           4 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
     341             : 
     342           4 :     int bIsLSB = poDS->hHeader.nByteOrder == 1 ? 1 : 0;
     343             : 
     344             :     auto poBand = std::make_unique<BYNRasterBand>(
     345           4 :         poDS.get(), 1, poDS->fpImage, BYN_HDR_SZ, nDTSize,
     346          12 :         poDS->nRasterXSize * nDTSize, eDT, CPL_IS_LSB == bIsLSB);
     347           4 :     if (!poBand->IsValid())
     348           0 :         return nullptr;
     349           4 :     poDS->SetBand(1, std::move(poBand));
     350             : 
     351             :     /* -------------------------------------------------------------------- */
     352             :     /*      Initialize any PAM information.                                 */
     353             :     /* -------------------------------------------------------------------- */
     354             : 
     355           4 :     poDS->SetDescription(poOpenInfo->pszFilename);
     356           4 :     poDS->TryLoadXML();
     357             : 
     358             :     /* -------------------------------------------------------------------- */
     359             :     /*      Check for overviews.                                            */
     360             :     /* -------------------------------------------------------------------- */
     361             : 
     362           4 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     363             : 
     364           4 :     return poDS.release();
     365             : }
     366             : 
     367             : /************************************************************************/
     368             : /*                          GetGeoTransform()                           */
     369             : /************************************************************************/
     370             : 
     371           0 : CPLErr BYNDataset::GetGeoTransform(double *padfTransform)
     372             : 
     373             : {
     374           0 :     memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
     375           0 :     return CE_None;
     376             : }
     377             : 
     378             : /************************************************************************/
     379             : /*                          GetSpatialRef()                             */
     380             : /************************************************************************/
     381             : 
     382           0 : const OGRSpatialReference *BYNDataset::GetSpatialRef() const
     383             : 
     384             : {
     385           0 :     if (!m_oSRS.IsEmpty())
     386           0 :         return &m_oSRS;
     387             : 
     388             :     /* Try to use a prefefined EPSG compound CS */
     389             : 
     390           0 :     if (hHeader.nDatum == 1 && hHeader.nVDatum == 2)
     391             :     {
     392           0 :         m_oSRS.importFromEPSG(BYN_DATUM_1_VDATUM_2);
     393           0 :         return &m_oSRS;
     394             :     }
     395             : 
     396             :     /* Build the GEOGCS based on Datum ( or Ellipsoid )*/
     397             : 
     398           0 :     bool bNoGeogCS = false;
     399             : 
     400           0 :     if (hHeader.nDatum == 0)
     401           0 :         m_oSRS.importFromEPSG(BYN_DATUM_0);
     402           0 :     else if (hHeader.nDatum == 1)
     403           0 :         m_oSRS.importFromEPSG(BYN_DATUM_1);
     404             :     else
     405             :     {
     406             :         /* Build GEOGCS based on Ellipsoid (Table 3) */
     407             : 
     408           0 :         if (hHeader.nEllipsoid > -1 &&
     409           0 :             hHeader.nEllipsoid <
     410             :                 static_cast<GInt16>(CPL_ARRAYSIZE(EllipsoidTable)))
     411           0 :             m_oSRS.SetGeogCS(
     412           0 :                 CPLSPrintf("BYN Ellipsoid(%d)", hHeader.nEllipsoid),
     413           0 :                 "Unspecified", EllipsoidTable[hHeader.nEllipsoid].pszName,
     414           0 :                 EllipsoidTable[hHeader.nEllipsoid].dfSemiMajor,
     415           0 :                 EllipsoidTable[hHeader.nEllipsoid].dfInvFlattening);
     416             :         else
     417           0 :             bNoGeogCS = true;
     418             :     }
     419             : 
     420             :     /* Build the VERT_CS based on VDatum */
     421             : 
     422           0 :     OGRSpatialReference oSRSComp;
     423           0 :     OGRSpatialReference oSRSVert;
     424             : 
     425           0 :     int nVertCS = 0;
     426             : 
     427           0 :     if (hHeader.nVDatum == 1)
     428           0 :         nVertCS = BYN_VDATUM_1;
     429           0 :     else if (hHeader.nVDatum == 2)
     430           0 :         nVertCS = BYN_VDATUM_2;
     431           0 :     else if (hHeader.nVDatum == 3)
     432           0 :         nVertCS = BYN_VDATUM_3;
     433             :     else
     434             :     {
     435             :         /* Return GEOGCS ( .err files ) */
     436             : 
     437           0 :         if (bNoGeogCS)
     438           0 :             return nullptr;
     439             : 
     440           0 :         return &m_oSRS;
     441             :     }
     442             : 
     443           0 :     oSRSVert.importFromEPSG(nVertCS);
     444             : 
     445             :     /* Create CPMPD_CS with GEOGCS and VERT_CS */
     446             : 
     447           0 :     if (oSRSComp.SetCompoundCS(CPLSPrintf("BYN Datum(%d) & VDatum(%d)",
     448           0 :                                           hHeader.nDatum, hHeader.nDatum),
     449           0 :                                &m_oSRS, &oSRSVert) == CE_None)
     450             :     {
     451             :         /* Return COMPD_CS with GEOGCS and VERT_CS */
     452             : 
     453           0 :         m_oSRS = std::move(oSRSComp);
     454           0 :         m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     455           0 :         return &m_oSRS;
     456             :     }
     457             : 
     458           0 :     return nullptr;
     459             : }
     460             : 
     461             : /*----------------------------------------------------------------------*/
     462             : /*                           buffer2header()                            */
     463             : /*----------------------------------------------------------------------*/
     464             : 
     465          12 : void BYNDataset::buffer2header(const GByte *pabyBuf, BYNHeader *pohHeader)
     466             : 
     467             : {
     468          12 :     memcpy(&pohHeader->nSouth, pabyBuf, 4);
     469          12 :     memcpy(&pohHeader->nNorth, pabyBuf + 4, 4);
     470          12 :     memcpy(&pohHeader->nWest, pabyBuf + 8, 4);
     471          12 :     memcpy(&pohHeader->nEast, pabyBuf + 12, 4);
     472          12 :     memcpy(&pohHeader->nDLat, pabyBuf + 16, 2);
     473          12 :     memcpy(&pohHeader->nDLon, pabyBuf + 18, 2);
     474          12 :     memcpy(&pohHeader->nGlobal, pabyBuf + 20, 2);
     475          12 :     memcpy(&pohHeader->nType, pabyBuf + 22, 2);
     476          12 :     memcpy(&pohHeader->dfFactor, pabyBuf + 24, 8);
     477          12 :     memcpy(&pohHeader->nSizeOf, pabyBuf + 32, 2);
     478          12 :     memcpy(&pohHeader->nVDatum, pabyBuf + 34, 2);
     479          12 :     memcpy(&pohHeader->nDescrip, pabyBuf + 40, 2);
     480          12 :     memcpy(&pohHeader->nSubType, pabyBuf + 42, 2);
     481          12 :     memcpy(&pohHeader->nDatum, pabyBuf + 44, 2);
     482          12 :     memcpy(&pohHeader->nEllipsoid, pabyBuf + 46, 2);
     483          12 :     memcpy(&pohHeader->nByteOrder, pabyBuf + 48, 2);
     484          12 :     memcpy(&pohHeader->nScale, pabyBuf + 50, 2);
     485          12 :     memcpy(&pohHeader->dfWo, pabyBuf + 52, 8);
     486          12 :     memcpy(&pohHeader->dfGM, pabyBuf + 60, 8);
     487          12 :     memcpy(&pohHeader->nTideSys, pabyBuf + 68, 2);
     488          12 :     memcpy(&pohHeader->nRealiz, pabyBuf + 70, 2);
     489          12 :     memcpy(&pohHeader->dEpoch, pabyBuf + 72, 4);
     490          12 :     memcpy(&pohHeader->nPtType, pabyBuf + 76, 2);
     491             : 
     492             : #if defined(CPL_MSB)
     493             :     CPL_LSBPTR32(&pohHeader->nSouth);
     494             :     CPL_LSBPTR32(&pohHeader->nNorth);
     495             :     CPL_LSBPTR32(&pohHeader->nWest);
     496             :     CPL_LSBPTR32(&pohHeader->nEast);
     497             :     CPL_LSBPTR16(&pohHeader->nDLat);
     498             :     CPL_LSBPTR16(&pohHeader->nDLon);
     499             :     CPL_LSBPTR16(&pohHeader->nGlobal);
     500             :     CPL_LSBPTR16(&pohHeader->nType);
     501             :     CPL_LSBPTR64(&pohHeader->dfFactor);
     502             :     CPL_LSBPTR16(&pohHeader->nSizeOf);
     503             :     CPL_LSBPTR16(&pohHeader->nVDatum);
     504             :     CPL_LSBPTR16(&pohHeader->nDescrip);
     505             :     CPL_LSBPTR16(&pohHeader->nSubType);
     506             :     CPL_LSBPTR16(&pohHeader->nDatum);
     507             :     CPL_LSBPTR16(&pohHeader->nEllipsoid);
     508             :     CPL_LSBPTR16(&pohHeader->nByteOrder);
     509             :     CPL_LSBPTR16(&pohHeader->nScale);
     510             :     CPL_LSBPTR64(&pohHeader->dfWo);
     511             :     CPL_LSBPTR64(&pohHeader->dfGM);
     512             :     CPL_LSBPTR16(&pohHeader->nTideSys);
     513             :     CPL_LSBPTR16(&pohHeader->nRealiz);
     514             :     CPL_LSBPTR32(&pohHeader->dEpoch);
     515             :     CPL_LSBPTR16(&pohHeader->nPtType);
     516             : #endif
     517             : 
     518             : #if DEBUG
     519          12 :     CPLDebug("BYN", "South         = %d", pohHeader->nSouth);
     520          12 :     CPLDebug("BYN", "North         = %d", pohHeader->nNorth);
     521          12 :     CPLDebug("BYN", "West          = %d", pohHeader->nWest);
     522          12 :     CPLDebug("BYN", "East          = %d", pohHeader->nEast);
     523          12 :     CPLDebug("BYN", "DLat          = %d", pohHeader->nDLat);
     524          12 :     CPLDebug("BYN", "DLon          = %d", pohHeader->nDLon);
     525          12 :     CPLDebug("BYN", "DGlobal       = %d", pohHeader->nGlobal);
     526          12 :     CPLDebug("BYN", "DType         = %d", pohHeader->nType);
     527          12 :     CPLDebug("BYN", "Factor        = %f", pohHeader->dfFactor);
     528          12 :     CPLDebug("BYN", "SizeOf        = %d", pohHeader->nSizeOf);
     529          12 :     CPLDebug("BYN", "VDatum        = %d", pohHeader->nVDatum);
     530          12 :     CPLDebug("BYN", "Data          = %d", pohHeader->nDescrip);
     531          12 :     CPLDebug("BYN", "SubType       = %d", pohHeader->nSubType);
     532          12 :     CPLDebug("BYN", "Datum         = %d", pohHeader->nDatum);
     533          12 :     CPLDebug("BYN", "Ellipsoid     = %d", pohHeader->nEllipsoid);
     534          12 :     CPLDebug("BYN", "ByteOrder     = %d", pohHeader->nByteOrder);
     535          12 :     CPLDebug("BYN", "Scale         = %d", pohHeader->nScale);
     536          12 :     CPLDebug("BYN", "Wo            = %f", pohHeader->dfWo);
     537          12 :     CPLDebug("BYN", "GM            = %f", pohHeader->dfGM);
     538          12 :     CPLDebug("BYN", "TideSystem    = %d", pohHeader->nTideSys);
     539          12 :     CPLDebug("BYN", "RefRealzation = %d", pohHeader->nRealiz);
     540          12 :     CPLDebug("BYN", "Epoch         = %f", pohHeader->dEpoch);
     541          12 :     CPLDebug("BYN", "PtType        = %d", pohHeader->nPtType);
     542             : #endif
     543          12 : }
     544             : 
     545             : /************************************************************************/
     546             : /*                          GDALRegister_BYN()                          */
     547             : /************************************************************************/
     548             : 
     549        1667 : void GDALRegister_BYN()
     550             : 
     551             : {
     552        1667 :     if (GDALGetDriverByName("BYN") != nullptr)
     553         282 :         return;
     554             : 
     555        1385 :     GDALDriver *poDriver = new GDALDriver();
     556             : 
     557        1385 :     poDriver->SetDescription("BYN");
     558        1385 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     559        1385 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
     560        1385 :                               "Natural Resources Canada's Geoid");
     561        1385 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "byn err");
     562        1385 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     563        1385 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/byn.html");
     564             : 
     565        1385 :     poDriver->pfnOpen = BYNDataset::Open;
     566        1385 :     poDriver->pfnIdentify = BYNDataset::Identify;
     567             : 
     568        1385 :     GetGDALDriverManager()->RegisterDriver(poDriver);
     569             : }

Generated by: LCOV version 1.14