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