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 >) 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 : }
|