1 : /******************************************************************************
2 : * $Id: srtmhgtdataset.cpp 18117 2009-11-27 19:42:29Z rouault $
3 : *
4 : * Project: SRTM HGT Driver
5 : * Purpose: SRTM HGT File Read Support.
6 : * http://dds.cr.usgs.gov/srtm/version2_1/Documentation/SRTM_Topo.pdf
7 : * http://www2.jpl.nasa.gov/srtm/faq.html
8 : * http://dds.cr.usgs.gov/srtm/version2_1
9 : * Authors: Michael Mazzella, Even Rouault
10 : *
11 : ******************************************************************************
12 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : ****************************************************************************/
32 :
33 : #include "gdal_pam.h"
34 : #include "cpl_port.h"
35 : #include "cpl_string.h"
36 : #include "ogr_spatialref.h"
37 :
38 : #define SRTMHG_NODATA_VALUE -32768
39 :
40 : CPL_CVSID("$Id: srtmhgtdataset.cpp 18117 2009-11-27 19:42:29Z rouault $");
41 :
42 : CPL_C_START
43 : void GDALRegister_SRTMHGT(void);
44 : CPL_C_END
45 :
46 : /************************************************************************/
47 : /* ==================================================================== */
48 : /* SRTMHGTDataset */
49 : /* ==================================================================== */
50 : /************************************************************************/
51 :
52 : class SRTMHGTRasterBand;
53 :
54 : class SRTMHGTDataset : public GDALPamDataset
55 : {
56 : friend class SRTMHGTRasterBand;
57 :
58 : FILE* fpImage;
59 : double adfGeoTransform[6];
60 : GInt16* panBuffer;
61 :
62 : public:
63 : SRTMHGTDataset();
64 : ~SRTMHGTDataset();
65 :
66 : virtual const char *GetProjectionRef(void);
67 : virtual CPLErr GetGeoTransform(double*);
68 :
69 : static int Identify( GDALOpenInfo * poOpenInfo );
70 : static GDALDataset* Open(GDALOpenInfo*);
71 : static GDALDataset* CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
72 : int bStrict, char ** papszOptions,
73 : GDALProgressFunc pfnProgress, void * pProgressData );
74 :
75 : };
76 :
77 : /************************************************************************/
78 : /* ==================================================================== */
79 : /* SRTMHGTRasterBand */
80 : /* ==================================================================== */
81 : /************************************************************************/
82 :
83 : class SRTMHGTRasterBand : public GDALPamRasterBand
84 10 : {
85 : friend class SRTMHGTDataset;
86 :
87 : int bNoDataSet;
88 : double dfNoDataValue;
89 :
90 : public:
91 : SRTMHGTRasterBand(SRTMHGTDataset*, int);
92 :
93 : virtual CPLErr IReadBlock(int, int, void*);
94 : virtual CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void* pImage);
95 :
96 : virtual GDALColorInterp GetColorInterpretation();
97 :
98 : virtual double GetNoDataValue( int *pbSuccess = NULL );
99 :
100 3 : virtual const char* GetUnitType() { return "m"; }
101 : };
102 :
103 : /************************************************************************/
104 : /* SRTMHGTRasterBand() */
105 : /************************************************************************/
106 :
107 5 : SRTMHGTRasterBand::SRTMHGTRasterBand(SRTMHGTDataset* poDS, int nBand)
108 : {
109 5 : this->poDS = poDS;
110 5 : this->nBand = nBand;
111 5 : eDataType = GDT_Int16;
112 5 : nBlockXSize = poDS->nRasterXSize;
113 5 : nBlockYSize = 1;
114 5 : bNoDataSet = TRUE;
115 5 : dfNoDataValue = SRTMHG_NODATA_VALUE;
116 5 : }
117 :
118 : /************************************************************************/
119 : /* IReadBlock() */
120 : /************************************************************************/
121 :
122 3603 : CPLErr SRTMHGTRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
123 : void* pImage)
124 : {
125 3603 : SRTMHGTDataset* poGDS = (SRTMHGTDataset*) poDS;
126 :
127 : CPLAssert(nBlockXOff == 0);
128 3603 : if(nBlockXOff != 0)
129 : {
130 : CPLError(CE_Failure, CPLE_NotSupported,
131 0 : "unhandled nBlockXOff value : %d", nBlockXOff);
132 0 : return CE_Failure;
133 : }
134 :
135 3603 : if((poGDS == NULL) || (poGDS->fpImage == NULL))
136 0 : return CE_Failure;
137 :
138 : /* -------------------------------------------------------------------- */
139 : /* Load the desired data into the working buffer. */
140 : /* -------------------------------------------------------------------- */
141 3603 : VSIFSeekL(poGDS->fpImage, nBlockYOff*nBlockXSize*2, SEEK_SET);
142 3603 : VSIFReadL((unsigned char*)pImage, nBlockXSize, 2, poGDS->fpImage);
143 : #ifdef CPL_LSB
144 3603 : GDALSwapWords(pImage, 2, nBlockXSize, 2);
145 : #endif
146 :
147 3603 : return CE_None;
148 : }
149 :
150 : /************************************************************************/
151 : /* IWriteBlock() */
152 : /************************************************************************/
153 :
154 0 : CPLErr SRTMHGTRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void* pImage)
155 : {
156 0 : SRTMHGTDataset* poGDS = (SRTMHGTDataset*) poDS;
157 :
158 : CPLAssert(nBlockXOff == 0);
159 0 : if(nBlockXOff != 0)
160 : {
161 0 : CPLError(CE_Failure, CPLE_NotSupported, "unhandled nBlockXOff value : %d", nBlockXOff);
162 0 : return CE_Failure;
163 : }
164 :
165 0 : if((poGDS == NULL) || (poGDS->fpImage == NULL) || (poGDS->eAccess != GA_Update))
166 0 : return CE_Failure;
167 :
168 0 : VSIFSeekL(poGDS->fpImage, nBlockYOff*nBlockXSize*2, SEEK_SET);
169 :
170 : #ifdef CPL_LSB
171 0 : memcpy(poGDS->panBuffer, pImage, nBlockXSize*sizeof(GInt16));
172 0 : GDALSwapWords(poGDS->panBuffer, 2, nBlockXSize, 2);
173 0 : VSIFWriteL((unsigned char*)poGDS->panBuffer, nBlockXSize, 2, poGDS->fpImage);
174 : #else
175 : VSIFWriteL((unsigned char*)pImage, nBlockXSize, 2, poGDS->fpImage);
176 : #endif
177 :
178 0 : return CE_None;
179 : }
180 : /************************************************************************/
181 : /* GetNoDataValue() */
182 : /************************************************************************/
183 :
184 5 : double SRTMHGTRasterBand::GetNoDataValue( int * pbSuccess )
185 :
186 : {
187 5 : if( pbSuccess )
188 4 : *pbSuccess = bNoDataSet;
189 :
190 5 : return dfNoDataValue;
191 : }
192 :
193 : /************************************************************************/
194 : /* GetColorInterpretation() */
195 : /************************************************************************/
196 :
197 2 : GDALColorInterp SRTMHGTRasterBand::GetColorInterpretation()
198 : {
199 2 : return GCI_Undefined;
200 : }
201 :
202 : /************************************************************************/
203 : /* ==================================================================== */
204 : /* SRTMHGTDataset */
205 : /* ==================================================================== */
206 : /************************************************************************/
207 :
208 :
209 : /************************************************************************/
210 : /* SRTMHGTDataset() */
211 : /************************************************************************/
212 :
213 5 : SRTMHGTDataset::SRTMHGTDataset()
214 : {
215 5 : adfGeoTransform[0] = 0.0;
216 5 : adfGeoTransform[1] = 1.0;
217 5 : adfGeoTransform[2] = 0.0;
218 5 : adfGeoTransform[3] = 0.0;
219 5 : adfGeoTransform[4] = 0.0;
220 5 : adfGeoTransform[5] = 1.0;
221 5 : fpImage = NULL;
222 5 : panBuffer = NULL;
223 5 : }
224 :
225 : /************************************************************************/
226 : /* ~SRTMHGTDataset() */
227 : /************************************************************************/
228 :
229 10 : SRTMHGTDataset::~SRTMHGTDataset()
230 : {
231 5 : FlushCache();
232 5 : if(fpImage != NULL)
233 5 : VSIFCloseL(fpImage);
234 5 : CPLFree(panBuffer);
235 10 : }
236 :
237 : /************************************************************************/
238 : /* GetGeoTransform() */
239 : /************************************************************************/
240 :
241 4 : CPLErr SRTMHGTDataset::GetGeoTransform(double * padfTransform)
242 : {
243 4 : memcpy(padfTransform, adfGeoTransform, sizeof(double)*6);
244 4 : return CE_None;
245 : }
246 :
247 : /************************************************************************/
248 : /* GetProjectionRef() */
249 : /************************************************************************/
250 :
251 6 : const char *SRTMHGTDataset::GetProjectionRef()
252 :
253 : {
254 6 : return( SRS_WKT_WGS84 );
255 : }
256 :
257 : /************************************************************************/
258 : /* Identify() */
259 : /************************************************************************/
260 :
261 9510 : int SRTMHGTDataset::Identify( GDALOpenInfo * poOpenInfo )
262 :
263 : {
264 9510 : const char* fileName = CPLGetFilename(poOpenInfo->pszFilename);
265 9510 : if( strlen(fileName) < 11 || !EQUALN(&fileName[7], ".hgt", 4) )
266 9503 : return FALSE;
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* We check the file size to see if it is 25,934,402 bytes */
270 : /* (SRTM 1) or 2,884,802 bytes (SRTM 3) */
271 : /* -------------------------------------------------------------------- */
272 : VSIStatBufL fileStat;
273 :
274 7 : if(VSIStatL(poOpenInfo->pszFilename, &fileStat) != 0)
275 2 : return FALSE;
276 5 : if(fileStat.st_size != 25934402 && fileStat.st_size != 2884802)
277 0 : return FALSE;
278 :
279 5 : return TRUE;
280 : }
281 :
282 : /************************************************************************/
283 : /* Open() */
284 : /************************************************************************/
285 :
286 1781 : GDALDataset* SRTMHGTDataset::Open(GDALOpenInfo* poOpenInfo)
287 : {
288 1781 : if (!Identify(poOpenInfo))
289 1776 : return NULL;
290 :
291 5 : const char* fileName = CPLGetFilename(poOpenInfo->pszFilename);
292 :
293 : char latLonValueString[4];
294 5 : memset(latLonValueString, 0, 4);
295 5 : strncpy(latLonValueString, &fileName[1], 2);
296 5 : int southWestLat = atoi(latLonValueString);
297 5 : memset(latLonValueString, 0, 4);
298 5 : strncpy(latLonValueString, &fileName[4], 3);
299 5 : int southWestLon = atoi(latLonValueString);
300 :
301 10 : if(fileName[0] == 'N' || fileName[0] == 'n')
302 5 : southWestLat = southWestLat;
303 0 : else if(fileName[0] == 'S' || fileName[0] == 's')
304 0 : southWestLat = southWestLat * -1;
305 : else
306 0 : return NULL;
307 :
308 5 : if(fileName[3] == 'E' || fileName[3] == 'e')
309 0 : southWestLon = southWestLon;
310 10 : else if(fileName[3] == 'W' || fileName[3] == 'w')
311 5 : southWestLon = southWestLon * -1;
312 : else
313 0 : return NULL;
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Create a corresponding GDALDataset. */
317 : /* -------------------------------------------------------------------- */
318 : SRTMHGTDataset* poDS;
319 :
320 5 : poDS = new SRTMHGTDataset();
321 :
322 : /* -------------------------------------------------------------------- */
323 : /* Open the file using the large file api. */
324 : /* -------------------------------------------------------------------- */
325 5 : poDS->fpImage = VSIFOpenL(poOpenInfo->pszFilename, (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb");
326 5 : if(poDS->fpImage == NULL)
327 : {
328 0 : CPLError(CE_Failure, CPLE_OpenFailed, "VSIFOpenL(%s) failed unexpectedly in srtmhgtdataset.cpp", poOpenInfo->pszFilename);
329 0 : return NULL;
330 : }
331 :
332 : VSIStatBufL fileStat;
333 5 : if(VSIStatL(poOpenInfo->pszFilename, &fileStat) != 0)
334 : {
335 0 : return NULL;
336 : }
337 5 : int numPixels = (fileStat.st_size == 25934402) ? 3601 : /* 2884802 */ 1201;
338 :
339 5 : poDS->eAccess = poOpenInfo->eAccess;
340 : #ifdef CPL_LSB
341 5 : if(poDS->eAccess == GA_Update)
342 : {
343 0 : poDS->panBuffer = (GInt16*) CPLMalloc(numPixels * sizeof(GInt16));
344 : }
345 : #endif
346 :
347 : /* -------------------------------------------------------------------- */
348 : /* Capture some information from the file that is of interest. */
349 : /* -------------------------------------------------------------------- */
350 5 : poDS->nRasterXSize = numPixels;
351 5 : poDS->nRasterYSize = numPixels;
352 5 : poDS->nBands = 1;
353 :
354 5 : poDS->adfGeoTransform[0] = southWestLon - 0.5 / (numPixels - 1);
355 5 : poDS->adfGeoTransform[1] = 1.0 / (numPixels-1);
356 5 : poDS->adfGeoTransform[2] = 0.0000000000;
357 5 : poDS->adfGeoTransform[3] = southWestLat + 1 + 0.5 / (numPixels - 1);
358 5 : poDS->adfGeoTransform[4] = 0.0000000000;
359 5 : poDS->adfGeoTransform[5] = -1.0 / (numPixels-1);
360 :
361 5 : poDS->SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Create band information object. */
365 : /* -------------------------------------------------------------------- */
366 5 : SRTMHGTRasterBand* tmpBand = new SRTMHGTRasterBand(poDS, 1);
367 5 : poDS->SetBand(1, tmpBand);
368 :
369 : /* -------------------------------------------------------------------- */
370 : /* Initialize any PAM information. */
371 : /* -------------------------------------------------------------------- */
372 5 : poDS->SetDescription(poOpenInfo->pszFilename);
373 5 : poDS->TryLoadXML();
374 :
375 : /* -------------------------------------------------------------------- */
376 : /* Support overviews. */
377 : /* -------------------------------------------------------------------- */
378 5 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
379 :
380 5 : return poDS;
381 : }
382 :
383 : /************************************************************************/
384 : /* CreateCopy() */
385 : /************************************************************************/
386 :
387 18 : GDALDataset * SRTMHGTDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
388 : int bStrict, char ** papszOptions,
389 : GDALProgressFunc pfnProgress, void * pProgressData )
390 :
391 : {
392 18 : int nBands = poSrcDS->GetRasterCount();
393 18 : int nXSize = poSrcDS->GetRasterXSize();
394 18 : int nYSize = poSrcDS->GetRasterYSize();
395 :
396 18 : if( pfnProgress && !pfnProgress( 0.0, NULL, pProgressData ) )
397 0 : return NULL;
398 :
399 : /* -------------------------------------------------------------------- */
400 : /* Some some rudimentary checks */
401 : /* -------------------------------------------------------------------- */
402 18 : if (nBands == 0)
403 : {
404 : CPLError( CE_Failure, CPLE_NotSupported,
405 1 : "SRTMHGT driver does not support source dataset with zero band.\n");
406 1 : return NULL;
407 : }
408 17 : else if (nBands != 1)
409 : {
410 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
411 4 : "SRTMHGT driver only uses the first band of the dataset.\n");
412 4 : if (bStrict)
413 4 : return NULL;
414 : }
415 :
416 : /* -------------------------------------------------------------------- */
417 : /* Checks the input SRS */
418 : /* -------------------------------------------------------------------- */
419 13 : OGRSpatialReference ogrsr_input;
420 13 : OGRSpatialReference ogrsr_wgs84;
421 13 : char* c = (char*)poSrcDS->GetProjectionRef();
422 13 : ogrsr_input.importFromWkt(&c);
423 13 : ogrsr_wgs84.SetWellKnownGeogCS( "WGS84" );
424 13 : if ( ogrsr_input.IsSameGeogCS(&ogrsr_wgs84) == FALSE)
425 : {
426 : CPLError( CE_Warning, CPLE_AppDefined,
427 : "The source projection coordinate system is %s. Only WGS 84 is supported.\n"
428 : "The SRTMHGT driver will generate a file as if the source was WGS 84 projection coordinate system.",
429 0 : poSrcDS->GetProjectionRef() );
430 : }
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Work out the LL origin. */
434 : /* -------------------------------------------------------------------- */
435 : int nLLOriginLat, nLLOriginLong;
436 : double adfGeoTransform[6];
437 :
438 13 : if (poSrcDS->GetGeoTransform( adfGeoTransform ) != CE_None)
439 : {
440 : CPLError( CE_Failure, CPLE_AppDefined,
441 0 : "Source image must have a geo transform matrix.");
442 0 : return NULL;
443 : }
444 :
445 : nLLOriginLat = (int)
446 13 : floor(adfGeoTransform[3]
447 13 : + poSrcDS->GetRasterYSize() * adfGeoTransform[5] + 0.5);
448 :
449 13 : nLLOriginLong = (int) floor(adfGeoTransform[0] + 0.5);
450 :
451 28 : if (fabs(nLLOriginLat - (adfGeoTransform[3]
452 13 : + (poSrcDS->GetRasterYSize() - 0.5) * adfGeoTransform[5])) > 1e-10 ||
453 2 : fabs(nLLOriginLong - (adfGeoTransform[0] + 0.5 * adfGeoTransform[1])) > 1e-10)
454 : {
455 : CPLError( CE_Warning, CPLE_AppDefined,
456 : "The corner coordinates of the source are not properly "
457 11 : "aligned on plain latitude/longitude boundaries.");
458 : }
459 :
460 : /* -------------------------------------------------------------------- */
461 : /* Check image dimensions. */
462 : /* -------------------------------------------------------------------- */
463 13 : if (!((nXSize == 1201 && nYSize == 1201) || (nXSize == 3601 && nYSize == 3601)))
464 : {
465 : CPLError( CE_Failure, CPLE_AppDefined,
466 11 : "Image dimensions should be 1201x1201 or 3601x3601.");
467 11 : return NULL;
468 : }
469 :
470 : /* -------------------------------------------------------------------- */
471 : /* Check filename. */
472 : /* -------------------------------------------------------------------- */
473 : char expectedFileName[12];
474 : snprintf(expectedFileName, sizeof(expectedFileName), "%c%02d%c%03d.HGT",
475 : (nLLOriginLat >= 0) ? 'N' : 'S',
476 : (nLLOriginLat >= 0) ? nLLOriginLat : -nLLOriginLat,
477 : (nLLOriginLong >= 0) ? 'E' : 'W',
478 2 : (nLLOriginLong >= 0) ? nLLOriginLong : -nLLOriginLong);
479 2 : if (!EQUAL(expectedFileName, CPLGetFilename(pszFilename)))
480 : {
481 : CPLError( CE_Warning, CPLE_AppDefined,
482 0 : "Expected output filename is %s.", expectedFileName);
483 : }
484 :
485 : /* -------------------------------------------------------------------- */
486 : /* Write output file. */
487 : /* -------------------------------------------------------------------- */
488 2 : FILE* fp = VSIFOpenL(pszFilename, "wb");
489 :
490 2 : GInt16* panData = (GInt16*) CPLMalloc(sizeof(GInt16) * nXSize);
491 2 : GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(1);
492 :
493 : int bSrcBandHasNoData;
494 2 : double srcBandNoData = poSrcBand->GetNoDataValue(&bSrcBandHasNoData);
495 :
496 2404 : for( int iY = 0; iY < nYSize; iY++ )
497 : {
498 : poSrcBand->RasterIO( GF_Read, 0, iY, nXSize, 1,
499 : (void *) panData, nXSize, 1,
500 2402 : GDT_Int16, 0, 0 );
501 :
502 : /* Translate nodata values */
503 2402 : if (bSrcBandHasNoData && srcBandNoData != SRTMHG_NODATA_VALUE)
504 : {
505 0 : for( int iX = 0; iX < nXSize; iX++ )
506 : {
507 0 : if (panData[iX] == srcBandNoData)
508 0 : panData[iX] = SRTMHG_NODATA_VALUE;
509 : }
510 : }
511 :
512 : #ifdef CPL_LSB
513 2402 : GDALSwapWords(panData, 2, nXSize, 2);
514 : #endif
515 :
516 2402 : if( VSIFWriteL( panData,sizeof(GInt16) * nXSize,1,fp ) != 1)
517 : {
518 : CPLError( CE_Failure, CPLE_FileIO,
519 : "Failed to write line %d in SRTMHGT dataset.\n",
520 0 : iY );
521 0 : VSIFCloseL(fp);
522 0 : CPLFree( panData );
523 0 : return NULL;
524 : }
525 :
526 2402 : if( pfnProgress && !pfnProgress((iY+1) / (double) nYSize, NULL, pProgressData ) )
527 : {
528 : CPLError( CE_Failure, CPLE_UserInterrupt,
529 0 : "User terminated CreateCopy()" );
530 0 : VSIFCloseL(fp);
531 0 : CPLFree( panData );
532 0 : return NULL;
533 : }
534 : }
535 :
536 2 : CPLFree( panData );
537 2 : VSIFCloseL(fp);
538 :
539 : /* -------------------------------------------------------------------- */
540 : /* Reopen and copy missing information into a PAM file. */
541 : /* -------------------------------------------------------------------- */
542 : GDALPamDataset *poDS = (GDALPamDataset *)
543 2 : GDALOpen( pszFilename, GA_ReadOnly );
544 :
545 2 : if( poDS )
546 2 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT);
547 :
548 2 : return poDS;
549 : }
550 :
551 : /************************************************************************/
552 : /* GDALRegister_SRTMHGT() */
553 : /************************************************************************/
554 338 : void GDALRegister_SRTMHGT()
555 : {
556 : GDALDriver* poDriver;
557 :
558 338 : if(GDALGetDriverByName("SRTMHGT") == NULL)
559 : {
560 336 : poDriver = new GDALDriver();
561 336 : poDriver->SetDescription("SRTMHGT");
562 336 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SRTMHGT File Format");
563 336 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hgt");
564 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
565 336 : "frmt_various.html#SRTMHGT" );
566 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
567 336 : "Byte Int16 UInt16" );
568 :
569 336 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
570 :
571 336 : poDriver->pfnIdentify = SRTMHGTDataset::Identify;
572 336 : poDriver->pfnOpen = SRTMHGTDataset::Open;
573 336 : poDriver->pfnCreateCopy = SRTMHGTDataset::CreateCopy;
574 :
575 336 : GetGDALDriverManager()->RegisterDriver(poDriver);
576 : }
577 338 : }
578 :
|