root/tags/gdal_1_3_2/gcore/gdaldriver.cpp

Revision 9398, 19.6 kB (checked in by fwarmerdam, 3 years ago)

updated contact info

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  GDAL Core
5  * Purpose:  Implementation of GDALDriver class (and C wrappers)
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1998, 2000, Frank Warmerdam
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  * $Log$
31  * Revision 1.41  2006/03/28 14:49:56  fwarmerdam
32  * updated contact info
33  *
34  * Revision 1.40  2006/03/03 19:44:45  fwarmerdam
35  * force C numeric locale in select locations
36  *
37  * Revision 1.39  2006/02/07 19:07:07  fwarmerdam
38  * applied some strategic improved outofmemory checking
39  *
40  * Revision 1.38  2006/02/07 18:13:25  fwarmerdam
41  * Perform graceful error recovery if line buffer allocation fails.
42  *
43  * Revision 1.37  2005/10/13 01:38:29  fwarmerdam
44  * Ensure "large file" stat is used in GDALDriver::Delete() so it works
45  * on in-memory stuff.
46  *
47  * Revision 1.36  2005/10/13 00:46:19  fwarmerdam
48  * Avoid trying to set scale and offset if they are the defaults.
49  *
50  * Revision 1.35  2005/05/24 18:13:15  dron
51  * Added GDALGetDriverCreationOptionList() function.
52  *
53  * Revision 1.34  2005/05/17 15:13:06  fwarmerdam
54  * Added nodata support for bands
55  *
56  * Revision 1.33  2005/04/04 15:24:48  fwarmerdam
57  * Most C entry points now CPL_STDCALL
58  *
59  * Revision 1.32  2005/03/16 11:01:10  lichun
60  * in CreateCopy() the category names are copied as well
61  *
62  * Revision 1.31  2005/01/15 16:10:10  fwarmerdam
63  * added offset, scale and colorinterp to default createcopy
64  *
65  * Revision 1.30  2003/05/23 20:42:24  sperkins
66  * default CreateCopy() now copies metadata
67  *
68  * Revision 1.29  2003/04/30 17:13:48  warmerda
69  * added docs for many C functions
70  */
71
72 #include "gdal_priv.h"
73
74 CPL_CVSID("$Id$");
75
76 /************************************************************************/
77 /*                             GDALDriver()                             */
78 /************************************************************************/
79
80 GDALDriver::GDALDriver()
81
82 {
83     pfnOpen = NULL;
84     pfnCreate = NULL;
85     pfnDelete = NULL;
86     pfnCreateCopy = NULL;
87     pfnUnloadDriver = NULL;
88     pDriverData = NULL;
89 }
90
91 /************************************************************************/
92 /*                            ~GDALDriver()                             */
93 /************************************************************************/
94
95 GDALDriver::~GDALDriver()
96
97 {
98     if( pfnUnloadDriver != NULL )
99         pfnUnloadDriver( this );
100 }
101
102 /************************************************************************/
103 /*                               Create()                               */
104 /************************************************************************/
105
106 /**
107  * Create a new dataset with this driver.
108  *
109  * What argument values are legal for particular drivers is driver specific,
110  * and there is no way to query in advance to establish legal values.
111  *
112  * Equivelent of the C function GDALCreate().
113  *
114  * @param pszFilename the name of the dataset to create.
115  * @param nXSize width of created raster in pixels.
116  * @param nYSize height of created raster in pixels.
117  * @param nBands number of bands.
118  * @param eType type of raster.
119  * @param papszParmList list of driver specific control parameters.
120  *
121  * @return NULL on failure, or a new GDALDataset.
122  */
123
124 GDALDataset * GDALDriver::Create( const char * pszFilename,
125                                   int nXSize, int nYSize, int nBands,
126                                   GDALDataType eType, char ** papszParmList )
127
128 {
129     CPLLocaleC  oLocaleForcer;
130
131     /* notdef: should add a bunch of error checking here */
132
133     if( pfnCreate == NULL )
134     {
135         CPLError( CE_Failure, CPLE_NotSupported,
136                   "GDALDriver::Create() ... no create method implemented"
137                   " for this format.\n" );
138
139         return NULL;
140     }
141     else
142     {
143         GDALDataset *poDS;
144
145         CPLDebug( "GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
146                   GetDescription(), pszFilename, nXSize, nYSize, nBands,
147                   GDALGetDataTypeName( eType ),
148                   papszParmList );
149              
150         poDS = pfnCreate( pszFilename, nXSize, nYSize, nBands, eType,
151                           papszParmList );
152
153         if( poDS != NULL )
154         {
155             if( poDS->GetDescription() == NULL
156                 || strlen(poDS->GetDescription()) == 0 )
157                 poDS->SetDescription( pszFilename );
158
159             if( poDS->poDriver == NULL )
160                 poDS->poDriver = this;
161         }
162
163         return poDS;
164     }
165 }
166
167 /************************************************************************/
168 /*                             GDALCreate()                             */
169 /************************************************************************/
170
171 /**
172  * @see GDALDriver::Create()
173  */
174
175 GDALDatasetH CPL_DLL CPL_STDCALL
176 GDALCreate( GDALDriverH hDriver, const char * pszFilename,
177             int nXSize, int nYSize, int nBands, GDALDataType eBandType,
178             char ** papszOptions )
179
180 {
181     return( ((GDALDriver *) hDriver)->Create( pszFilename,
182                                               nXSize, nYSize, nBands,
183                                               eBandType, papszOptions ) );
184 }
185
186 /************************************************************************/
187 /*                             CreateCopy()                             */
188 /************************************************************************/
189
190 /**
191  * Create a copy of a dataset.
192  *
193  * This method will attempt to create a copy of a raster dataset with the
194  * indicated filename, and in this drivers format.  Band number, size,
195  * type, projection, geotransform and so forth are all to be copied from
196  * the provided template dataset. 
197  *
198  * Note that many sequential write once formats (such as JPEG and PNG) don't
199  * implement the Create() method but do implement this CreateCopy() method.
200  * If the driver doesn't implement CreateCopy(), but does implement Create()
201  * then the default CreateCopy() mechanism built on calling Create() will
202  * be used.                                                             
203  *
204  * It is intended that CreateCopy() would often be used with a source dataset
205  * which is a virtual dataset allowing configuration of band types, and
206  * other information without actually duplicating raster data.  This virtual
207  * dataset format hasn't yet been implemented at the time of this documentation
208  * being written.
209  *
210  * @param pszFilename the name for the new dataset.
211  * @param poSrcDS the dataset being duplicated.
212  * @param bStrict TRUE if the copy must be strictly equivelent, or more
213  * normally FALSE indicating that the copy may adapt as needed for the
214  * output format.
215  * @param papszOptions additional format dependent options controlling
216  * creation of the output file.
217  * @param pfnProgress a function to be used to report progress of the copy.
218  * @param pProgressData application data passed into progress function.
219  *
220  * @return a pointer to the newly created dataset (may be read-only access).
221  */
222
223 GDALDataset *GDALDriver::CreateCopy( const char * pszFilename,
224                                      GDALDataset * poSrcDS,
225                                      int bStrict, char ** papszOptions,
226                                      GDALProgressFunc pfnProgress,
227                                      void * pProgressData )
228
229 {
230     CPLLocaleC  oLocaleForcer;
231
232     if( pfnProgress == NULL )
233         pfnProgress = GDALDummyProgress;
234
235 /* -------------------------------------------------------------------- */
236 /*      If the format provides a CreateCopy() method use that,          */
237 /*      otherwise fallback to the internal implementation using the     */
238 /*      Create() method.                                                */
239 /* -------------------------------------------------------------------- */
240     if( pfnCreateCopy != NULL )
241     {
242         GDALDataset *poDstDS;
243
244         poDstDS = pfnCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
245                                  pfnProgress, pProgressData );
246         if( poDstDS != NULL )
247         {
248             if( poDstDS->GetDescription() == NULL
249                 || strlen(poDstDS->GetDescription()) > 0 )
250                 poDstDS->SetDescription( pszFilename );
251
252             if( poDstDS->poDriver == NULL )
253                 poDstDS->poDriver = this;
254         }
255
256         return poDstDS;
257     }
258    
259 /* -------------------------------------------------------------------- */
260 /*      Create destination dataset.                                     */
261 /* -------------------------------------------------------------------- */
262     GDALDataset  *poDstDS;
263     int          nXSize = poSrcDS->GetRasterXSize();
264     int          nYSize = poSrcDS->GetRasterYSize();
265     GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
266     CPLErr       eErr;
267
268     CPLDebug( "GDAL", "Using default GDALDriver::CreateCopy implementation." );
269
270     if( !pfnProgress( 0.0, NULL, pProgressData ) )
271     {
272         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
273         return NULL;
274     }
275
276     poDstDS = Create( pszFilename, nXSize, nYSize,
277                       poSrcDS->GetRasterCount(), eType, papszOptions );
278
279     if( poDstDS == NULL )
280         return NULL;
281
282 /* -------------------------------------------------------------------- */
283 /*      Try setting the projection and geotransform if it seems         */
284 /*      suitable.  For now we don't try and copy GCPs, though I         */
285 /*      suppose we should. Also copy metadata.                          */
286 /* -------------------------------------------------------------------- */
287     double      adfGeoTransform[6];
288
289     if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
290         && (adfGeoTransform[0] != 0.0
291             || adfGeoTransform[1] != 1.0
292             || adfGeoTransform[2] != 0.0
293             || adfGeoTransform[3] != 0.0
294             || adfGeoTransform[4] != 0.0
295             || adfGeoTransform[5] != 1.0) )
296     {
297         poDstDS->SetGeoTransform( adfGeoTransform );
298     }
299
300     if( poSrcDS->GetProjectionRef() != NULL
301         && strlen(poSrcDS->GetProjectionRef()) > 0 )
302     {
303         poDstDS->SetProjection( poSrcDS->GetProjectionRef() );
304     }
305
306     poDstDS->SetMetadata( poSrcDS->GetMetadata() );
307
308 /* -------------------------------------------------------------------- */
309 /*      Loop copying bands.                                             */
310 /* -------------------------------------------------------------------- */
311     for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
312     {
313         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
314         GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand+1 );
315
316 /* -------------------------------------------------------------------- */
317 /*      Do we need to copy a colortable or other metadata?              */
318 /* -------------------------------------------------------------------- */
319         GDALColorTable *poCT;
320         char** catNames;
321         int bSuccess;
322         double dfValue;
323
324         poCT = poSrcBand->GetColorTable();
325         if( poCT != NULL )
326             poDstBand->SetColorTable( poCT );
327
328         if( !bStrict )
329             CPLPushErrorHandler( CPLQuietErrorHandler );
330
331         if( strlen(poSrcBand->GetDescription()) > 0 )
332             poDstBand->SetDescription( poSrcBand->GetDescription() );
333
334         poDstBand->SetMetadata( poSrcBand->GetMetadata() );
335
336         dfValue = poSrcBand->GetOffset( &bSuccess );
337         if( bSuccess && dfValue != 0.0 )
338             poDstBand->SetOffset( dfValue );
339
340         dfValue = poSrcBand->GetScale( &bSuccess );
341         if( bSuccess && dfValue != 1.0 )
342             poDstBand->SetScale( dfValue );
343
344         dfValue = poSrcBand->GetNoDataValue( &bSuccess );
345         if( bSuccess )
346             poDstBand->SetNoDataValue( dfValue );
347
348         if( poSrcBand->GetColorInterpretation() != GCI_Undefined )
349             poDstBand->SetColorInterpretation(
350                 poSrcBand->GetColorInterpretation() );
351
352         catNames = poSrcBand->GetCategoryNames();
353         if (0 != catNames)
354             poDstBand->SetCategoryNames(catNames);
355
356         if( !bStrict )
357             CPLPopErrorHandler();
358
359 /* -------------------------------------------------------------------- */
360 /*      Copy image data.                                                */
361 /* -------------------------------------------------------------------- */
362         void           *pData;
363
364         pData = VSIMalloc(nXSize * GDALGetDataTypeSize(eType) / 8);
365         if( pData == NULL )
366         {
367             CPLError( CE_Failure, CPLE_OutOfMemory,
368                       "CreateCopy(): Out of memory allocating %d byte line buffer.\n",
369                       nXSize * GDALGetDataTypeSize(eType) / 8 );
370             delete poDstDS;
371             Delete( pszFilename );
372             return NULL;
373         }
374
375         for( int iLine = 0; iLine < nYSize; iLine++ )
376         {
377             eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
378                                         pData, nXSize, 1, eType, 0, 0 );
379             if( eErr != CE_None )
380             {
381                 delete poDstDS;
382                 Delete( pszFilename );
383                 return NULL;
384             }
385            
386             eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
387                                         pData, nXSize, 1, eType, 0, 0 );
388
389             if( eErr != CE_None )
390             {
391                 delete poDstDS;
392                 return NULL;
393             }
394
395             if( !pfnProgress( (iBand + (iLine+1) / (double) nYSize)
396                               / (double) poSrcDS->GetRasterCount(),
397                               NULL, pProgressData ) )
398             {
399                 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
400                 delete poDstDS;
401                 Delete( pszFilename );
402                 return NULL;
403             }
404         }
405
406         CPLFree( pData );
407     }
408
409     return poDstDS;
410 }
411
412 /************************************************************************/
413 /*                           GDALCreateCopy()                           */
414 /************************************************************************/
415
416 /**
417  * @see GDALDriver::CreateCopy()
418  */
419
420 GDALDatasetH CPL_STDCALL GDALCreateCopy( GDALDriverH hDriver,
421                              const char * pszFilename,
422                              GDALDatasetH hSrcDS,
423                              int bStrict, char ** papszOptions,
424                              GDALProgressFunc pfnProgress,
425                              void * pProgressData )
426
427 {
428     return (GDALDatasetH) ((GDALDriver *) hDriver)->
429         CreateCopy( pszFilename, (GDALDataset *) hSrcDS, bStrict, papszOptions,
430                     pfnProgress, pProgressData );
431 }
432
433 /************************************************************************/
434 /*                               Delete()                               */
435 /************************************************************************/
436
437 /**
438  * Delete named dataset.
439  *
440  * The driver will attempt to delete the named dataset in a driver specific
441  * fashion.  Full featured drivers will delete all associated files,
442  * database objects, or whatever is appropriate.  The default behaviour when
443  * no driver specific behaviour is provided is to attempt to delete the
444  * passed name as a single file.
445  *
446  * It is unwise to have open dataset handles on this dataset when it is
447  * deleted.
448  *
449  * Equivelent of the C function GDALDeleteDataset().
450  *
451  * @param pszFilename name of dataset to delete.
452  *
453  * @return CE_None on success, or CE_Failure if the operation fails.
454  */
455
456 CPLErr GDALDriver::Delete( const char * pszFilename )
457
458 {
459     if( pfnDelete != NULL )
460         return pfnDelete( pszFilename );
461     else
462     {
463         VSIStatBufL     sStat;
464
465         if( VSIStatL( pszFilename, &sStat ) == 0
466             && VSI_ISREG( sStat.st_mode ) )
467         {
468             if( VSIUnlink( pszFilename ) == 0 )
469                 return CE_None;
470             else
471             {
472                 CPLError( CE_Failure, CPLE_AppDefined,
473                           "%s: Attempt to unlink %s failed.\n",
474                           GetDescription(), pszFilename );
475                 return CE_Failure;
476             }
477         }
478         else
479         {
480             CPLError( CE_Failure, CPLE_AppDefined,
481                       "%s: Unable to delete %s, not a file.\n",
482                       GetDescription(), pszFilename );
483             return CE_Failure;
484         }
485     }
486 }
487
488 /************************************************************************/
489 /*                             GDALDelete()                             */
490 /************************************************************************/
491
492 /**
493  * @see GDALDriver::Delete()
494  */
495
496 CPLErr CPL_STDCALL GDALDeleteDataset( GDALDriverH hDriver, const char * pszFilename )
497
498 {
499     return ((GDALDriver *) hDriver)->Delete( pszFilename );
500 }
501
502 /************************************************************************/
503 /*                       GDALGetDriverShortName()                       */
504 /************************************************************************/
505
506 const char * CPL_STDCALL GDALGetDriverShortName( GDALDriverH hDriver )
507
508 {
509     if( hDriver == NULL )
510         return NULL;
511     else
512         return ((GDALDriver *) hDriver)->GetDescription();
513 }
514
515 /************************************************************************/
516 /*                       GDALGetDriverLongName()                        */
517 /************************************************************************/
518
519 const char * CPL_STDCALL GDALGetDriverLongName( GDALDriverH hDriver )
520
521 {
522     if( hDriver == NULL )
523         return NULL;
524
525     const char *pszLongName =
526         ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_LONGNAME );
527
528     if( pszLongName == NULL )
529         return "";
530     else
531         return pszLongName;
532 }
533
534 /************************************************************************/
535 /*                       GDALGetDriverHelpTopic()                       */
536 /************************************************************************/
537
538 const char * CPL_STDCALL GDALGetDriverHelpTopic( GDALDriverH hDriver )
539
540 {
541     if( hDriver == NULL )
542         return NULL;
543
544     return ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_HELPTOPIC );
545 }
546
547 /************************************************************************/
548 /*                   GDALGetDriverCreationOptionList()                  */
549 /************************************************************************/
550
551 const char * CPL_STDCALL GDALGetDriverCreationOptionList( GDALDriverH hDriver )
552
553 {
554     if( hDriver == NULL )
555         return NULL;
556
557     const char *pszOptionList =
558         ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST );
559
560     if( pszOptionList == NULL )
561         return "";
562     else
563         return pszOptionList;
564 }
Note: See TracBrowser for help on using the browser.