1 : /******************************************************************************
2 : * $Id: bagdataset.cpp 18000 2009-11-12 14:28:14Z warmerdam $
3 : *
4 : * Project: Hierarchical Data Format Release 5 (HDF5)
5 : * Purpose: Read BAG datasets.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gh5_convenience.h"
31 :
32 : #include "gdal_pam.h"
33 : #include "gdal_priv.h"
34 : #include "ogr_spatialref.h"
35 : #include "cpl_string.h"
36 :
37 : CPL_CVSID("$Id: bagdataset.cpp 18000 2009-11-12 14:28:14Z warmerdam $");
38 :
39 : CPL_C_START
40 : void GDALRegister_BAG(void);
41 : CPL_C_END
42 :
43 : OGRErr OGR_SRS_ImportFromISO19115( OGRSpatialReference *poThis,
44 : const char *pszISOXML );
45 :
46 : /************************************************************************/
47 : /* ==================================================================== */
48 : /* BAGDataset */
49 : /* ==================================================================== */
50 : /************************************************************************/
51 : class BAGDataset : public GDALPamDataset
52 : {
53 :
54 : friend class BAGRasterBand;
55 :
56 : hid_t hHDF5;
57 :
58 : char *pszProjection;
59 : double adfGeoTransform[6];
60 :
61 : void LoadMetadata();
62 :
63 : char *pszXMLMetadata;
64 : char *apszMDList[2];
65 :
66 : public:
67 : BAGDataset();
68 : ~BAGDataset();
69 :
70 : virtual CPLErr GetGeoTransform( double * );
71 : virtual const char *GetProjectionRef(void);
72 : virtual char **GetMetadata( const char * pszDomain = "" );
73 :
74 : static GDALDataset *Open( GDALOpenInfo * );
75 : static int Identify( GDALOpenInfo * );
76 : };
77 :
78 : /************************************************************************/
79 : /* ==================================================================== */
80 : /* BAGRasterBand */
81 : /* ==================================================================== */
82 : /************************************************************************/
83 : class BAGRasterBand : public GDALPamRasterBand
84 : {
85 : friend class BAGDataset;
86 :
87 : hid_t hDatasetID;
88 : hid_t native;
89 : hid_t dataspace;
90 :
91 : bool bMinMaxSet;
92 : double dfMinimum;
93 : double dfMaximum;
94 :
95 : public:
96 :
97 : BAGRasterBand( BAGDataset *, int );
98 : ~BAGRasterBand();
99 :
100 : bool Initialize( hid_t hDataset, const char *pszName );
101 :
102 : virtual CPLErr IReadBlock( int, int, void * );
103 : virtual double GetNoDataValue( int * );
104 :
105 : virtual double GetMinimum( int *pbSuccess = NULL );
106 : virtual double GetMaximum(int *pbSuccess = NULL );
107 : };
108 :
109 : /************************************************************************/
110 : /* BAGRasterBand() */
111 : /************************************************************************/
112 3 : BAGRasterBand::BAGRasterBand( BAGDataset *poDS, int nBand )
113 :
114 : {
115 3 : this->poDS = poDS;
116 3 : this->nBand = nBand;
117 :
118 3 : hDatasetID = -1;
119 3 : bMinMaxSet = false;
120 3 : }
121 :
122 : /************************************************************************/
123 : /* ~BAGRasterBand() */
124 : /************************************************************************/
125 :
126 6 : BAGRasterBand::~BAGRasterBand()
127 : {
128 6 : }
129 :
130 : /************************************************************************/
131 : /* Initialize() */
132 : /************************************************************************/
133 :
134 3 : bool BAGRasterBand::Initialize( hid_t hDatasetID, const char *pszName )
135 :
136 : {
137 3 : SetDescription( pszName );
138 :
139 3 : this->hDatasetID = hDatasetID;
140 :
141 3 : hid_t datatype = H5Dget_type( hDatasetID );
142 3 : dataspace = H5Dget_space( hDatasetID );
143 3 : hid_t n_dims = H5Sget_simple_extent_ndims( dataspace );
144 3 : native = H5Tget_native_type( datatype, H5T_DIR_ASCEND );
145 : hsize_t dims[3], maxdims[3];
146 :
147 3 : eDataType = GH5_GetDataType( native );
148 :
149 3 : if( n_dims == 2 )
150 : {
151 3 : H5Sget_simple_extent_dims( dataspace, dims, maxdims );
152 :
153 3 : nRasterXSize = dims[1];
154 3 : nRasterYSize = dims[0];
155 : }
156 : else
157 : {
158 : CPLError( CE_Failure, CPLE_AppDefined,
159 0 : "Dataset not of rank 2." );
160 0 : return false;
161 : }
162 :
163 3 : nBlockXSize = nRasterXSize;
164 3 : nBlockYSize = 1;
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* Check for chunksize, and use it as blocksize for optimized */
168 : /* reading. */
169 : /* -------------------------------------------------------------------- */
170 3 : hid_t listid = H5Dget_create_plist( hDatasetID );
171 3 : if (listid>0)
172 : {
173 3 : if(H5Pget_layout(listid) == H5D_CHUNKED)
174 : {
175 : hsize_t panChunkDims[3];
176 0 : int nDimSize = H5Pget_chunk(listid, 3, panChunkDims);
177 0 : nBlockXSize = panChunkDims[nDimSize-1];
178 0 : nBlockYSize = panChunkDims[nDimSize-2];
179 : }
180 3 : H5Pclose(listid);
181 : }
182 :
183 : /* -------------------------------------------------------------------- */
184 : /* Load min/max information. */
185 : /* -------------------------------------------------------------------- */
186 3 : if( EQUAL(pszName,"elevation")
187 : && GH5_FetchAttribute( hDatasetID, "Maximum Elevation Value",
188 : dfMaximum )
189 : && GH5_FetchAttribute( hDatasetID, "Minimum Elevation Value",
190 : dfMinimum ) )
191 1 : bMinMaxSet = true;
192 2 : else if( EQUAL(pszName,"uncertainty")
193 : && GH5_FetchAttribute( hDatasetID, "Maximum Uncertainty Value",
194 : dfMaximum )
195 : && GH5_FetchAttribute( hDatasetID, "Minimum Uncertainty Value",
196 : dfMinimum ) )
197 1 : bMinMaxSet = true;
198 1 : else if( EQUAL(pszName,"nominal_elevation")
199 : && GH5_FetchAttribute( hDatasetID, "max_value",
200 : dfMaximum )
201 : && GH5_FetchAttribute( hDatasetID, "min_value",
202 : dfMinimum ) )
203 1 : bMinMaxSet = true;
204 :
205 3 : return true;
206 : }
207 :
208 : /************************************************************************/
209 : /* GetMinimum() */
210 : /************************************************************************/
211 :
212 1 : double BAGRasterBand::GetMinimum( int * pbSuccess )
213 :
214 : {
215 1 : if( bMinMaxSet )
216 : {
217 1 : if( pbSuccess )
218 1 : *pbSuccess = TRUE;
219 1 : return dfMinimum;
220 : }
221 : else
222 0 : return GDALRasterBand::GetMinimum( pbSuccess );
223 : }
224 :
225 : /************************************************************************/
226 : /* GetMaximum() */
227 : /************************************************************************/
228 :
229 1 : double BAGRasterBand::GetMaximum( int * pbSuccess )
230 :
231 : {
232 1 : if( bMinMaxSet )
233 : {
234 1 : if( pbSuccess )
235 1 : *pbSuccess = TRUE;
236 1 : return dfMaximum;
237 : }
238 : else
239 0 : return GDALRasterBand::GetMaximum( pbSuccess );
240 : }
241 :
242 : /************************************************************************/
243 : /* GetNoDataValue() */
244 : /************************************************************************/
245 1 : double BAGRasterBand::GetNoDataValue( int * pbSuccess )
246 :
247 : {
248 1 : if( pbSuccess )
249 1 : *pbSuccess = TRUE;
250 :
251 1 : if( EQUAL(GetDescription(),"elevation") )
252 1 : return 1000000.0;
253 0 : else if( EQUAL(GetDescription(),"uncertainty") )
254 0 : return 0.0;
255 0 : else if( EQUAL(GetDescription(),"nominal_elevation") )
256 0 : return 1000000.0;
257 : else
258 0 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
259 : }
260 :
261 : /************************************************************************/
262 : /* IReadBlock() */
263 : /************************************************************************/
264 30 : CPLErr BAGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
265 : void * pImage )
266 : {
267 : herr_t status;
268 : hsize_t count[3];
269 : H5OFFSET_TYPE offset[3];
270 : hid_t memspace;
271 : hsize_t col_dims[3];
272 30 : hsize_t rank = 2;
273 :
274 30 : offset[0] = nRasterYSize - nBlockYOff*nBlockYSize - 1;
275 30 : offset[1] = nBlockXOff*nBlockXSize;
276 30 : count[0] = nBlockYSize;
277 30 : count[1] = nBlockXSize;
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Select block from file space */
281 : /* -------------------------------------------------------------------- */
282 : status = H5Sselect_hyperslab( dataspace,
283 : H5S_SELECT_SET,
284 : offset, NULL,
285 30 : count, NULL );
286 :
287 : /* -------------------------------------------------------------------- */
288 : /* Create memory space to receive the data */
289 : /* -------------------------------------------------------------------- */
290 30 : col_dims[0]=nBlockYSize;
291 30 : col_dims[1]=nBlockXSize;
292 30 : memspace = H5Screate_simple( rank, col_dims, NULL );
293 30 : H5OFFSET_TYPE mem_offset[3] = {0, 0, 0};
294 : status = H5Sselect_hyperslab(memspace,
295 : H5S_SELECT_SET,
296 : mem_offset, NULL,
297 30 : count, NULL);
298 :
299 : status = H5Dread ( hDatasetID,
300 : native,
301 : memspace,
302 : dataspace,
303 : H5P_DEFAULT,
304 30 : pImage );
305 :
306 30 : return CE_None;
307 : }
308 :
309 : /************************************************************************/
310 : /* ==================================================================== */
311 : /* BAGDataset */
312 : /* ==================================================================== */
313 : /************************************************************************/
314 :
315 : /************************************************************************/
316 : /* BAGDataset() */
317 : /************************************************************************/
318 :
319 1 : BAGDataset::BAGDataset()
320 : {
321 1 : hHDF5 = -1;
322 1 : pszXMLMetadata = NULL;
323 1 : pszProjection = NULL;
324 :
325 1 : adfGeoTransform[0] = 0.0;
326 1 : adfGeoTransform[1] = 1.0;
327 1 : adfGeoTransform[2] = 0.0;
328 1 : adfGeoTransform[3] = 0.0;
329 1 : adfGeoTransform[4] = 0.0;
330 1 : adfGeoTransform[5] = 1.0;
331 1 : }
332 :
333 : /************************************************************************/
334 : /* ~BAGDataset() */
335 : /************************************************************************/
336 2 : BAGDataset::~BAGDataset( )
337 : {
338 1 : FlushCache();
339 :
340 1 : if( hHDF5 >= 0 )
341 1 : H5Fclose( hHDF5 );
342 :
343 1 : CPLFree( pszXMLMetadata );
344 1 : CPLFree( pszProjection );
345 2 : }
346 :
347 : /************************************************************************/
348 : /* Identify() */
349 : /************************************************************************/
350 :
351 8458 : int BAGDataset::Identify( GDALOpenInfo * poOpenInfo )
352 :
353 : {
354 : /* -------------------------------------------------------------------- */
355 : /* Is it an HDF5 file? */
356 : /* -------------------------------------------------------------------- */
357 : static const char achSignature[] = "\211HDF\r\n\032\n";
358 :
359 8458 : if( poOpenInfo->pabyHeader == NULL
360 : || memcmp(poOpenInfo->pabyHeader,achSignature,8) != 0 )
361 8456 : return FALSE;
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Does it have the extension .bag? */
365 : /* -------------------------------------------------------------------- */
366 2 : if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"bag") )
367 1 : return FALSE;
368 :
369 1 : return TRUE;
370 : }
371 :
372 : /************************************************************************/
373 : /* Open() */
374 : /************************************************************************/
375 :
376 731 : GDALDataset *BAGDataset::Open( GDALOpenInfo * poOpenInfo )
377 :
378 : {
379 : /* -------------------------------------------------------------------- */
380 : /* Confirm that this appears to be a BAG file. */
381 : /* -------------------------------------------------------------------- */
382 731 : if( !Identify( poOpenInfo ) )
383 730 : return NULL;
384 :
385 : /* -------------------------------------------------------------------- */
386 : /* Confirm the requested access is supported. */
387 : /* -------------------------------------------------------------------- */
388 1 : if( poOpenInfo->eAccess == GA_Update )
389 : {
390 : CPLError( CE_Failure, CPLE_NotSupported,
391 0 : "The BAG driver does not support update access." );
392 0 : return NULL;
393 : }
394 :
395 : /* -------------------------------------------------------------------- */
396 : /* Open the file as an HDF5 file. */
397 : /* -------------------------------------------------------------------- */
398 : hid_t hHDF5 = H5Fopen( poOpenInfo->pszFilename,
399 1 : H5F_ACC_RDONLY, H5P_DEFAULT );
400 :
401 1 : if( hHDF5 < 0 )
402 0 : return NULL;
403 :
404 : /* -------------------------------------------------------------------- */
405 : /* Confirm it is a BAG dataset by checking for the */
406 : /* BAG_Root/Bag Version attribute. */
407 : /* -------------------------------------------------------------------- */
408 1 : hid_t hBagRoot = H5Gopen( hHDF5, "/BAG_root" );
409 1 : hid_t hVersion = -1;
410 :
411 1 : if( hBagRoot >= 0 )
412 1 : hVersion = H5Aopen_name( hBagRoot, "Bag Version" );
413 :
414 1 : if( hVersion < 0 )
415 : {
416 0 : H5Fclose( hHDF5 );
417 0 : return NULL;
418 : }
419 1 : H5Aclose( hVersion );
420 :
421 : /* -------------------------------------------------------------------- */
422 : /* Create a corresponding dataset. */
423 : /* -------------------------------------------------------------------- */
424 1 : BAGDataset *poDS = new BAGDataset();
425 :
426 1 : poDS->hHDF5 = hHDF5;
427 :
428 : /* -------------------------------------------------------------------- */
429 : /* Extract version as metadata. */
430 : /* -------------------------------------------------------------------- */
431 1 : CPLString osVersion;
432 :
433 2 : if( GH5_FetchAttribute( hBagRoot, "Bag Version", osVersion ) )
434 1 : poDS->SetMetadataItem( "BagVersion", osVersion );
435 :
436 : /* -------------------------------------------------------------------- */
437 : /* Fetch the elevation dataset and attach as a band. */
438 : /* -------------------------------------------------------------------- */
439 1 : int nNextBand = 1;
440 1 : hid_t hElevation = H5Dopen( hHDF5, "/BAG_root/elevation" );
441 1 : if( hElevation < 0 )
442 : {
443 0 : delete poDS;
444 0 : return NULL;
445 : }
446 :
447 1 : BAGRasterBand *poElevBand = new BAGRasterBand( poDS, nNextBand );
448 :
449 2 : if( !poElevBand->Initialize( hElevation, "elevation" ) )
450 : {
451 0 : delete poElevBand;
452 0 : delete poDS;
453 0 : return NULL;
454 : }
455 :
456 1 : poDS->nRasterXSize = poElevBand->nRasterXSize;
457 1 : poDS->nRasterYSize = poElevBand->nRasterYSize;
458 :
459 1 : poDS->SetBand( nNextBand++, poElevBand );
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Try to do the same for the uncertainty band. */
463 : /* -------------------------------------------------------------------- */
464 1 : hid_t hUncertainty = H5Dopen( hHDF5, "/BAG_root/uncertainty" );
465 1 : BAGRasterBand *poUBand = new BAGRasterBand( poDS, nNextBand );
466 :
467 2 : if( hUncertainty >= 0 && poUBand->Initialize( hUncertainty, "uncertainty") )
468 : {
469 1 : poDS->SetBand( nNextBand++, poUBand );
470 : }
471 : else
472 0 : delete poUBand;
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Try to do the same for the uncertainty band. */
476 : /* -------------------------------------------------------------------- */
477 1 : hid_t hNominal = -1;
478 :
479 1 : H5E_BEGIN_TRY {
480 1 : hNominal = H5Dopen( hHDF5, "/BAG_root/nominal_elevation" );
481 1 : } H5E_END_TRY;
482 :
483 1 : BAGRasterBand *poNBand = new BAGRasterBand( poDS, nNextBand );
484 2 : if( hNominal >= 0 && poNBand->Initialize( hNominal,
485 : "nominal_elevation" ) )
486 : {
487 1 : poDS->SetBand( nNextBand++, poNBand );
488 : }
489 : else
490 0 : delete poNBand;
491 :
492 : /* -------------------------------------------------------------------- */
493 : /* Load the XML metadata. */
494 : /* -------------------------------------------------------------------- */
495 1 : poDS->LoadMetadata();
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* Setup/check for pam .aux.xml. */
499 : /* -------------------------------------------------------------------- */
500 1 : poDS->TryLoadXML();
501 :
502 : /* -------------------------------------------------------------------- */
503 : /* Setup overviews. */
504 : /* -------------------------------------------------------------------- */
505 1 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
506 :
507 1 : return( poDS );
508 : }
509 :
510 : /************************************************************************/
511 : /* LoadMetadata() */
512 : /************************************************************************/
513 :
514 1 : void BAGDataset::LoadMetadata()
515 :
516 : {
517 : /* -------------------------------------------------------------------- */
518 : /* Load the metadata from the file. */
519 : /* -------------------------------------------------------------------- */
520 1 : hid_t hMDDS = H5Dopen( hHDF5, "/BAG_root/metadata" );
521 1 : hid_t datatype = H5Dget_type( hMDDS );
522 1 : hid_t dataspace = H5Dget_space( hMDDS );
523 1 : hid_t native = H5Tget_native_type( datatype, H5T_DIR_ASCEND );
524 : hsize_t dims[3], maxdims[3];
525 :
526 1 : H5Sget_simple_extent_dims( dataspace, dims, maxdims );
527 :
528 1 : pszXMLMetadata = (char *) CPLCalloc(dims[0]+1,1);
529 :
530 1 : H5Dread( hMDDS, native, H5S_ALL, dataspace, H5P_DEFAULT, pszXMLMetadata );
531 :
532 1 : H5Dclose( hMDDS );
533 :
534 1 : if( strlen(pszXMLMetadata) == 0 )
535 0 : return;
536 :
537 : /* -------------------------------------------------------------------- */
538 : /* Try to get the geotransform. */
539 : /* -------------------------------------------------------------------- */
540 1 : CPLXMLNode *psRoot = CPLParseXMLString( pszXMLMetadata );
541 :
542 1 : if( psRoot == NULL )
543 0 : return;
544 :
545 1 : CPLStripXMLNamespace( psRoot, NULL, TRUE );
546 :
547 1 : CPLXMLNode *psGeo = CPLSearchXMLNode( psRoot, "=MD_Georectified" );
548 :
549 1 : if( psGeo != NULL )
550 : {
551 : char **papszCornerTokens =
552 : CSLTokenizeStringComplex(
553 : CPLGetXMLValue( psGeo, "cornerPoints.Point.coordinates", "" ),
554 1 : " ,", FALSE, FALSE );
555 :
556 1 : if( CSLCount(papszCornerTokens ) == 4 )
557 : {
558 1 : double dfLLX = atof( papszCornerTokens[0] );
559 1 : double dfLLY = atof( papszCornerTokens[1] );
560 1 : double dfURX = atof( papszCornerTokens[2] );
561 1 : double dfURY = atof( papszCornerTokens[3] );
562 :
563 1 : adfGeoTransform[0] = dfLLX;
564 1 : adfGeoTransform[1] = (dfURX - dfLLX) / (GetRasterXSize()-1);
565 1 : adfGeoTransform[3] = dfURY;
566 1 : adfGeoTransform[5] = (dfLLY - dfURY) / (GetRasterYSize()-1);
567 :
568 1 : adfGeoTransform[0] -= adfGeoTransform[1] * 0.5;
569 1 : adfGeoTransform[3] -= adfGeoTransform[5] * 0.5;
570 : }
571 1 : CSLDestroy( papszCornerTokens );
572 : }
573 :
574 1 : CPLDestroyXMLNode( psRoot );
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Try to get the coordinate system. */
578 : /* -------------------------------------------------------------------- */
579 1 : OGRSpatialReference oSRS;
580 :
581 1 : if( OGR_SRS_ImportFromISO19115( &oSRS, pszXMLMetadata )
582 : == OGRERR_NONE )
583 : {
584 0 : oSRS.exportToWkt( &pszProjection );
585 1 : }
586 : }
587 :
588 : /************************************************************************/
589 : /* GetGeoTransform() */
590 : /************************************************************************/
591 :
592 0 : CPLErr BAGDataset::GetGeoTransform( double *padfGeoTransform )
593 :
594 : {
595 0 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[3] != 0.0 )
596 : {
597 0 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double)*6 );
598 0 : return CE_None;
599 : }
600 : else
601 0 : return GDALPamDataset::GetGeoTransform( padfGeoTransform );
602 : }
603 :
604 : /************************************************************************/
605 : /* GetProjectionRef() */
606 : /************************************************************************/
607 :
608 0 : const char *BAGDataset::GetProjectionRef()
609 :
610 : {
611 0 : if( pszProjection )
612 0 : return pszProjection;
613 : else
614 0 : return GDALPamDataset::GetProjectionRef();
615 : }
616 :
617 : /************************************************************************/
618 : /* GetMetadata() */
619 : /************************************************************************/
620 :
621 0 : char **BAGDataset::GetMetadata( const char *pszDomain )
622 :
623 : {
624 0 : if( pszDomain != NULL && EQUAL(pszDomain,"xml:BAG") )
625 : {
626 0 : apszMDList[0] = pszXMLMetadata;
627 0 : apszMDList[1] = NULL;
628 :
629 0 : return apszMDList;
630 : }
631 : else
632 0 : return GDALPamDataset::GetMetadata( pszDomain );
633 : }
634 :
635 : /************************************************************************/
636 : /* GDALRegister_BAG() */
637 : /************************************************************************/
638 338 : void GDALRegister_BAG( )
639 :
640 : {
641 : GDALDriver *poDriver;
642 :
643 338 : if (! GDAL_CHECK_VERSION("BAG"))
644 0 : return;
645 :
646 338 : if( GDALGetDriverByName( "BAG" ) == NULL )
647 : {
648 336 : poDriver = new GDALDriver();
649 :
650 336 : poDriver->SetDescription( "BAG" );
651 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
652 336 : "Bathymetry Attributed Grid" );
653 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
654 336 : "frmt_bag.html" );
655 336 : poDriver->pfnOpen = BAGDataset::Open;
656 336 : poDriver->pfnIdentify = BAGDataset::Identify;
657 :
658 336 : GetGDALDriverManager( )->RegisterDriver( poDriver );
659 : }
660 : }
|