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

Generated by: LCOV version 1.14