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