1 : /******************************************************************************
2 : * $Id $
3 : *
4 : * Project: SPOT Dimap Driver
5 : * Purpose: Implementation of SPOT Dimap driver.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : * Docs: http://www.spotimage.fr/dimap/spec/documentation/refdoc.htm
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "gdal_pam.h"
33 : #include "cpl_minixml.h"
34 : #include "ogr_spatialref.h"
35 : #include "gdal_proxy.h"
36 :
37 : CPL_CVSID("$Id: dimapdataset.cpp 22012 2011-03-22 23:47:56Z warmerdam $");
38 :
39 : CPL_C_START
40 : void GDALRegister_DIMAP(void);
41 : CPL_C_END
42 :
43 : /************************************************************************/
44 : /* ==================================================================== */
45 : /* DIMAPDataset */
46 : /* ==================================================================== */
47 : /************************************************************************/
48 :
49 : class DIMAPDataset : public GDALPamDataset
50 : {
51 : CPLXMLNode *psProduct;
52 :
53 : GDALDataset *poImageDS;
54 :
55 : int nGCPCount;
56 : GDAL_GCP *pasGCPList;
57 : char *pszGCPProjection;
58 :
59 : CPLString osProjection;
60 :
61 : int bHaveGeoTransform;
62 : double adfGeoTransform[6];
63 :
64 : char **papszXMLDimapMetadata;
65 :
66 : protected:
67 : virtual int CloseDependentDatasets();
68 :
69 : public:
70 : DIMAPDataset();
71 : ~DIMAPDataset();
72 :
73 : virtual const char *GetProjectionRef(void);
74 : virtual CPLErr GetGeoTransform( double * );
75 : virtual int GetGCPCount();
76 : virtual const char *GetGCPProjection();
77 : virtual const GDAL_GCP *GetGCPs();
78 : virtual char **GetMetadata( const char *pszDomain );
79 : virtual char **GetFileList(void);
80 :
81 : static int Identify( GDALOpenInfo * );
82 : static GDALDataset *Open( GDALOpenInfo * );
83 :
84 : CPLXMLNode *GetProduct() { return psProduct; }
85 : };
86 :
87 : /************************************************************************/
88 : /* ==================================================================== */
89 : /* DIMAPWrapperRasterBand */
90 : /* ==================================================================== */
91 : /************************************************************************/
92 : class DIMAPWrapperRasterBand : public GDALProxyRasterBand
93 : {
94 : GDALRasterBand* poBaseBand;
95 :
96 : protected:
97 112 : virtual GDALRasterBand* RefUnderlyingRasterBand() { return poBaseBand; }
98 :
99 : public:
100 2 : DIMAPWrapperRasterBand( GDALRasterBand* poBaseBand )
101 2 : {
102 2 : this->poBaseBand = poBaseBand;
103 2 : eDataType = poBaseBand->GetRasterDataType();
104 2 : poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
105 2 : }
106 2 : ~DIMAPWrapperRasterBand() {}
107 : };
108 : /************************************************************************/
109 : /* ==================================================================== */
110 : /* DIMAPDataset */
111 : /* ==================================================================== */
112 : /************************************************************************/
113 :
114 : /************************************************************************/
115 : /* DIMAPDataset() */
116 : /************************************************************************/
117 :
118 2 : DIMAPDataset::DIMAPDataset()
119 : {
120 2 : psProduct = NULL;
121 :
122 2 : nGCPCount = 0;
123 2 : pasGCPList = NULL;
124 2 : pszGCPProjection = CPLStrdup("");
125 :
126 2 : poImageDS = NULL;
127 2 : bHaveGeoTransform = FALSE;
128 :
129 2 : papszXMLDimapMetadata = NULL;
130 2 : }
131 :
132 : /************************************************************************/
133 : /* ~DIMAPDataset() */
134 : /************************************************************************/
135 :
136 2 : DIMAPDataset::~DIMAPDataset()
137 :
138 : {
139 2 : FlushCache();
140 :
141 2 : CPLDestroyXMLNode( psProduct );
142 :
143 2 : CPLFree( pszGCPProjection );
144 2 : if( nGCPCount > 0 )
145 : {
146 2 : GDALDeinitGCPs( nGCPCount, pasGCPList );
147 2 : CPLFree( pasGCPList );
148 : }
149 :
150 2 : CSLDestroy(papszXMLDimapMetadata);
151 :
152 2 : CloseDependentDatasets();
153 2 : }
154 :
155 :
156 : /************************************************************************/
157 : /* CloseDependentDatasets() */
158 : /************************************************************************/
159 :
160 2 : int DIMAPDataset::CloseDependentDatasets()
161 : {
162 2 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
163 :
164 2 : if( poImageDS != NULL )
165 : {
166 2 : delete poImageDS;
167 2 : poImageDS = NULL;
168 2 : bHasDroppedRef = TRUE;
169 : }
170 :
171 : /* -------------------------------------------------------------------- */
172 : /* Disconnect the bands so our destructor doesn't try and */
173 : /* delete them since they really belonged to poImageDS. */
174 : /* -------------------------------------------------------------------- */
175 : int iBand;
176 4 : for( iBand = 0; iBand < nBands; iBand++ )
177 2 : delete papoBands[iBand];
178 2 : nBands = 0;
179 :
180 2 : return bHasDroppedRef;
181 : }
182 :
183 : /************************************************************************/
184 : /* GetMetadata() */
185 : /* */
186 : /* We implement special support for fetching the full product */
187 : /* metadata as xml. */
188 : /************************************************************************/
189 :
190 2 : char **DIMAPDataset::GetMetadata( const char *pszDomain )
191 :
192 : {
193 2 : if( pszDomain && EQUAL(pszDomain,"xml:dimap") )
194 : {
195 0 : if (papszXMLDimapMetadata == NULL)
196 : {
197 0 : papszXMLDimapMetadata = (char **) CPLCalloc(sizeof(char*),2);
198 0 : papszXMLDimapMetadata[0] = CPLSerializeXMLTree( psProduct );
199 : }
200 0 : return papszXMLDimapMetadata;
201 : }
202 : else
203 2 : return GDALPamDataset::GetMetadata( pszDomain );
204 : }
205 :
206 : /************************************************************************/
207 : /* GetProjectionRef() */
208 : /************************************************************************/
209 :
210 0 : const char *DIMAPDataset::GetProjectionRef()
211 :
212 : {
213 0 : if( strlen(osProjection) > 0 )
214 0 : return osProjection;
215 : else
216 0 : return GDALPamDataset::GetProjectionRef();
217 : }
218 :
219 : /************************************************************************/
220 : /* GetGeoTransform() */
221 : /************************************************************************/
222 :
223 0 : CPLErr DIMAPDataset::GetGeoTransform( double *padfGeoTransform )
224 :
225 : {
226 0 : if( bHaveGeoTransform )
227 : {
228 0 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double)*6 );
229 0 : return CE_None;
230 : }
231 : else
232 0 : return GDALPamDataset::GetGeoTransform( padfGeoTransform );
233 : }
234 :
235 : /************************************************************************/
236 : /* GetFileList() */
237 : /************************************************************************/
238 :
239 0 : char **DIMAPDataset::GetFileList()
240 :
241 : {
242 0 : char **papszFileList = GDALPamDataset::GetFileList();
243 0 : char **papszImageFiles = poImageDS->GetFileList();
244 :
245 0 : papszFileList = CSLInsertStrings( papszFileList, -1, papszImageFiles );
246 :
247 0 : CSLDestroy( papszImageFiles );
248 :
249 0 : return papszFileList;
250 : }
251 :
252 : /************************************************************************/
253 : /* Identify() */
254 : /************************************************************************/
255 :
256 12353 : int DIMAPDataset::Identify( GDALOpenInfo * poOpenInfo )
257 :
258 : {
259 12353 : if( poOpenInfo->nHeaderBytes >= 100 )
260 : {
261 1391 : if( strstr((const char *) poOpenInfo->pabyHeader,
262 : "<Dimap_Document" ) == NULL )
263 1389 : return FALSE;
264 : else
265 2 : return TRUE;
266 : }
267 10962 : else if( poOpenInfo->bIsDirectory )
268 : {
269 : VSIStatBufL sStat;
270 :
271 : CPLString osMDFilename =
272 42 : CPLFormCIFilename( poOpenInfo->pszFilename, "METADATA.DIM", NULL );
273 :
274 42 : if( VSIStatL( osMDFilename, &sStat ) == 0 )
275 0 : return TRUE;
276 : else
277 42 : return FALSE;
278 : }
279 :
280 10920 : return FALSE;
281 : }
282 :
283 : /************************************************************************/
284 : /* Open() */
285 : /************************************************************************/
286 :
287 3107 : GDALDataset *DIMAPDataset::Open( GDALOpenInfo * poOpenInfo )
288 :
289 : {
290 3107 : if( !Identify( poOpenInfo ) )
291 3105 : return NULL;
292 :
293 : /* -------------------------------------------------------------------- */
294 : /* Confirm the requested access is supported. */
295 : /* -------------------------------------------------------------------- */
296 2 : if( poOpenInfo->eAccess == GA_Update )
297 : {
298 : CPLError( CE_Failure, CPLE_NotSupported,
299 : "The DIMAP driver does not support update access to existing"
300 0 : " datasets.\n" );
301 0 : return NULL;
302 : }
303 : /* -------------------------------------------------------------------- */
304 : /* Get the metadata filename. */
305 : /* -------------------------------------------------------------------- */
306 2 : CPLString osMDFilename;
307 :
308 2 : if( poOpenInfo->bIsDirectory )
309 : {
310 : osMDFilename =
311 0 : CPLFormCIFilename( poOpenInfo->pszFilename, "METADATA.DIM", NULL );
312 : }
313 : else
314 2 : osMDFilename = poOpenInfo->pszFilename;
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* Ingest the xml file. */
318 : /* -------------------------------------------------------------------- */
319 : CPLXMLNode *psProduct, *psImageAttributes;
320 :
321 2 : psProduct = CPLParseXMLFile( osMDFilename );
322 2 : if( psProduct == NULL )
323 0 : return NULL;
324 :
325 2 : CPLXMLNode *psDoc = CPLGetXMLNode( psProduct, "=Dimap_Document" );
326 2 : psImageAttributes = CPLGetXMLNode( psDoc, "Raster_Dimensions" );
327 2 : if( psImageAttributes == NULL )
328 : {
329 : CPLError( CE_Failure, CPLE_OpenFailed,
330 0 : "Failed to find <Raster_Dimensions> in document." );
331 0 : return NULL;
332 : }
333 :
334 :
335 : /* -------------------------------------------------------------------- */
336 : /* Create the dataset. */
337 : /* -------------------------------------------------------------------- */
338 2 : DIMAPDataset *poDS = new DIMAPDataset();
339 :
340 2 : poDS->psProduct = psProduct;
341 :
342 : /* -------------------------------------------------------------------- */
343 : /* Get overall image information. */
344 : /* -------------------------------------------------------------------- */
345 : #ifdef DEBUG
346 : int nBands =
347 4 : atoi(CPLGetXMLValue( psImageAttributes, "NBANDS", "-1" ));
348 : #endif
349 :
350 : poDS->nRasterXSize =
351 2 : atoi(CPLGetXMLValue( psImageAttributes, "NCOLS", "-1" ));
352 : poDS->nRasterYSize =
353 2 : atoi(CPLGetXMLValue( psImageAttributes, "NROWS", "-1" ));
354 :
355 : /* -------------------------------------------------------------------- */
356 : /* Get the name of the underlying file. */
357 : /* -------------------------------------------------------------------- */
358 : const char *pszHref = CPLGetXMLValue(
359 2 : psDoc, "Data_Access.Data_File.DATA_FILE_PATH.href", "" );
360 2 : CPLString osPath = CPLGetPath(osMDFilename);
361 : CPLString osImageFilename =
362 2 : CPLFormFilename( osPath, pszHref, NULL );
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* Try and open the file. */
366 : /* -------------------------------------------------------------------- */
367 2 : poDS->poImageDS = (GDALDataset *) GDALOpen( osImageFilename, GA_ReadOnly );
368 2 : if( poDS->poImageDS == NULL )
369 : {
370 0 : delete poDS;
371 0 : return NULL;
372 : }
373 :
374 : /* -------------------------------------------------------------------- */
375 : /* Attach the bands. */
376 : /* -------------------------------------------------------------------- */
377 : int iBand;
378 2 : CPLAssert( nBands == poDS->poImageDS->GetRasterCount() );
379 :
380 4 : for( iBand = 1; iBand <= poDS->poImageDS->GetRasterCount(); iBand++ )
381 2 : poDS->SetBand( iBand, new DIMAPWrapperRasterBand(poDS->poImageDS->GetRasterBand( iBand )) );
382 :
383 : /* -------------------------------------------------------------------- */
384 : /* Try to collect simple insertion point. */
385 : /* -------------------------------------------------------------------- */
386 : CPLXMLNode *psGeoLoc =
387 2 : CPLGetXMLNode( psDoc, "Geoposition.Geoposition_Insert" );
388 :
389 2 : if( psGeoLoc != NULL )
390 : {
391 0 : poDS->bHaveGeoTransform = TRUE;
392 0 : poDS->adfGeoTransform[0] = atof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
393 0 : poDS->adfGeoTransform[1] = atof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
394 0 : poDS->adfGeoTransform[2] = 0.0;
395 0 : poDS->adfGeoTransform[3] = atof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
396 0 : poDS->adfGeoTransform[4] = 0.0;
397 0 : poDS->adfGeoTransform[5] = -atof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
398 : }
399 :
400 : /* -------------------------------------------------------------------- */
401 : /* Collect GCPs. */
402 : /* -------------------------------------------------------------------- */
403 2 : psGeoLoc = CPLGetXMLNode( psDoc, "Geoposition.Geoposition_Points" );
404 :
405 2 : if( psGeoLoc != NULL )
406 : {
407 : CPLXMLNode *psNode;
408 :
409 : // count gcps.
410 2 : poDS->nGCPCount = 0;
411 10 : for( psNode = psGeoLoc->psChild; psNode != NULL;
412 : psNode = psNode->psNext )
413 : {
414 8 : if( EQUAL(psNode->pszValue,"Tie_Point") )
415 8 : poDS->nGCPCount++ ;
416 : }
417 :
418 : poDS->pasGCPList = (GDAL_GCP *)
419 2 : CPLCalloc(sizeof(GDAL_GCP),poDS->nGCPCount);
420 :
421 2 : poDS->nGCPCount = 0;
422 :
423 10 : for( psNode = psGeoLoc->psChild; psNode != NULL;
424 : psNode = psNode->psNext )
425 : {
426 : char szID[32];
427 8 : GDAL_GCP *psGCP = poDS->pasGCPList + poDS->nGCPCount;
428 :
429 8 : if( !EQUAL(psNode->pszValue,"Tie_Point") )
430 0 : continue;
431 :
432 8 : poDS->nGCPCount++ ;
433 :
434 8 : sprintf( szID, "%d", poDS->nGCPCount );
435 8 : psGCP->pszId = CPLStrdup( szID );
436 8 : psGCP->pszInfo = CPLStrdup("");
437 : psGCP->dfGCPPixel =
438 8 : atof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_X","0"))-0.5;
439 : psGCP->dfGCPLine =
440 8 : atof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_Y","0"))-0.5;
441 : psGCP->dfGCPX =
442 8 : atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_X",""));
443 : psGCP->dfGCPY =
444 8 : atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Y",""));
445 : psGCP->dfGCPZ =
446 8 : atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Z",""));
447 : }
448 : }
449 :
450 : /* -------------------------------------------------------------------- */
451 : /* Collect the CRS. For now we look only for EPSG codes. */
452 : /* -------------------------------------------------------------------- */
453 : const char *pszSRS = CPLGetXMLValue(
454 : psDoc,
455 : "Coordinate_Reference_System.Horizontal_CS.HORIZONTAL_CS_CODE",
456 2 : NULL );
457 :
458 2 : if( pszSRS != NULL )
459 : {
460 2 : OGRSpatialReference oSRS;
461 2 : if( oSRS.SetFromUserInput( pszSRS ) == OGRERR_NONE )
462 : {
463 2 : if( poDS->nGCPCount > 0 )
464 : {
465 2 : CPLFree(poDS->pszGCPProjection);
466 2 : oSRS.exportToWkt( &(poDS->pszGCPProjection) );
467 : }
468 : else
469 : {
470 0 : char *pszProjection = NULL;
471 0 : oSRS.exportToWkt( &pszProjection );
472 0 : poDS->osProjection = pszProjection;
473 0 : CPLFree( pszProjection );
474 : }
475 2 : }
476 : }
477 : else
478 : {
479 : // Check underlying raster for SRS. We have cases where
480 : // HORIZONTAL_CS_CODE is empty and the underlying raster
481 : // is georeferenced (rprinceley).
482 0 : if ( poDS->poImageDS->GetProjectionRef() )
483 : {
484 0 : poDS->osProjection = poDS->poImageDS->GetProjectionRef();
485 : }
486 : }
487 :
488 : /* -------------------------------------------------------------------- */
489 : /* Translate other metadata of interest. */
490 : /* -------------------------------------------------------------------- */
491 : static const char *apszMetadataTranslation[] =
492 : {
493 : "Production", "",
494 : "Production.Facility", "FACILITY_",
495 : "Dataset_Sources.Source_Information.Scene_Source", "",
496 : "Data_Processing", "",
497 : "Image_Interpretation.Spectral_Band_Info", "SPECTRAL_",
498 : NULL, NULL
499 : };
500 :
501 : int iTrItem;
502 :
503 12 : for( iTrItem = 0; apszMetadataTranslation[iTrItem] != NULL; iTrItem += 2 )
504 : {
505 : CPLXMLNode *psParent =
506 10 : CPLGetXMLNode( psDoc, apszMetadataTranslation[iTrItem] );
507 :
508 10 : if( psParent == NULL )
509 2 : continue;
510 :
511 : // hackey logic to support directly access a name/value entry
512 : // or a parent element with many name/values.
513 :
514 : CPLXMLNode *psTarget;
515 8 : if( psParent->psChild != NULL
516 : && psParent->psChild->eType == CXT_Text )
517 0 : psTarget = psParent;
518 : else
519 8 : psTarget = psParent->psChild;
520 :
521 70 : for( ; psTarget != NULL && psTarget != psParent;
522 : psTarget = psTarget->psNext )
523 : {
524 62 : if( psTarget->eType == CXT_Element
525 : && psTarget->psChild != NULL
526 : && psTarget->psChild->eType == CXT_Text )
527 : {
528 54 : CPLString osName = apszMetadataTranslation[iTrItem+1];
529 :
530 54 : osName += psTarget->pszValue;
531 54 : poDS->SetMetadataItem( osName, psTarget->psChild->pszValue );
532 : }
533 : }
534 : }
535 :
536 : /* -------------------------------------------------------------------- */
537 : /* Set Band metadata from the <Spectral_Band_Info> content */
538 : /* -------------------------------------------------------------------- */
539 :
540 : CPLXMLNode *psImageInterpretationNode =
541 2 : CPLGetXMLNode( psDoc, "Image_Interpretation" );
542 2 : if (psImageInterpretationNode != NULL)
543 : {
544 2 : CPLXMLNode *psSpectralBandInfoNode = psImageInterpretationNode->psChild;
545 6 : while (psSpectralBandInfoNode != NULL)
546 : {
547 2 : if (psSpectralBandInfoNode->eType == CXT_Element &&
548 : EQUAL(psSpectralBandInfoNode->pszValue, "Spectral_Band_Info"))
549 : {
550 2 : CPLXMLNode *psTag = psSpectralBandInfoNode->psChild;
551 2 : int nBandIndex = 0;
552 16 : while(psTag != NULL)
553 : {
554 12 : if (psTag->eType == CXT_Element && psTag->psChild != NULL &&
555 : psTag->psChild->eType == CXT_Text && psTag->pszValue != NULL)
556 : {
557 12 : if (EQUAL(psTag->pszValue, "BAND_INDEX"))
558 : {
559 2 : nBandIndex = atoi(psTag->psChild->pszValue);
560 2 : if (nBandIndex <= 0 ||
561 : nBandIndex > poDS->poImageDS->GetRasterCount())
562 : {
563 : CPLError(CE_Warning, CPLE_AppDefined,
564 0 : "Bad BAND_INDEX value : %s", psTag->psChild->pszValue);
565 0 : nBandIndex = 0;
566 : }
567 : }
568 10 : else if (nBandIndex >= 1)
569 : {
570 : poDS->GetRasterBand(nBandIndex)->SetMetadataItem(
571 10 : psTag->pszValue, psTag->psChild->pszValue);
572 : }
573 : }
574 12 : psTag = psTag->psNext;
575 : }
576 : }
577 2 : psSpectralBandInfoNode = psSpectralBandInfoNode->psNext;
578 : }
579 : }
580 :
581 : /* -------------------------------------------------------------------- */
582 : /* Initialize any PAM information. */
583 : /* -------------------------------------------------------------------- */
584 2 : poDS->SetDescription( osMDFilename );
585 2 : poDS->TryLoadXML();
586 :
587 : /* -------------------------------------------------------------------- */
588 : /* Check for overviews. */
589 : /* -------------------------------------------------------------------- */
590 2 : poDS->oOvManager.Initialize( poDS, osMDFilename );
591 :
592 2 : return( poDS );
593 : }
594 :
595 : /************************************************************************/
596 : /* GetGCPCount() */
597 : /************************************************************************/
598 :
599 1 : int DIMAPDataset::GetGCPCount()
600 :
601 : {
602 1 : return nGCPCount;
603 : }
604 :
605 : /************************************************************************/
606 : /* GetGCPProjection() */
607 : /************************************************************************/
608 :
609 1 : const char *DIMAPDataset::GetGCPProjection()
610 :
611 : {
612 1 : return pszGCPProjection;
613 : }
614 :
615 : /************************************************************************/
616 : /* GetGCPs() */
617 : /************************************************************************/
618 :
619 1 : const GDAL_GCP *DIMAPDataset::GetGCPs()
620 :
621 : {
622 1 : return pasGCPList;
623 : }
624 :
625 : /************************************************************************/
626 : /* GDALRegister_DIMAP() */
627 : /************************************************************************/
628 :
629 558 : void GDALRegister_DIMAP()
630 :
631 : {
632 : GDALDriver *poDriver;
633 :
634 558 : if( GDALGetDriverByName( "DIMAP" ) == NULL )
635 : {
636 537 : poDriver = new GDALDriver();
637 :
638 537 : poDriver->SetDescription( "DIMAP" );
639 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
640 537 : "SPOT DIMAP" );
641 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
642 537 : "frmt_various.html#DIMAP" );
643 537 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
644 :
645 537 : poDriver->pfnOpen = DIMAPDataset::Open;
646 537 : poDriver->pfnIdentify = DIMAPDataset::Identify;
647 :
648 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
649 : }
650 558 : }
651 :
|