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

Generated by: LCOV version 1.14