ultimatepp/bazaar/plugin/geotiff/libgeotiff/gcore/gdaldriver.cpp
cxl b67920c1ca bazaar: plugin/geotiff
git-svn-id: svn://ultimatepp.org/upp/trunk@7587 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2014-08-12 18:56:26 +00:00

1374 lines
50 KiB
C++

/******************************************************************************
* $Id: gdaldriver.cpp 15685 2008-11-04 21:15:58Z rouault $
*
* Project: GDAL Core
* Purpose: Implementation of GDALDriver class (and C wrappers)
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1998, 2000, Frank Warmerdam
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "gdal_priv.h"
CPL_CVSID("$Id: gdaldriver.cpp 15685 2008-11-04 21:15:58Z rouault $");
/************************************************************************/
/* GDALDriver() */
/************************************************************************/
GDALDriver::GDALDriver()
{
pfnOpen = NULL;
pfnCreate = NULL;
pfnDelete = NULL;
pfnCreateCopy = NULL;
pfnUnloadDriver = NULL;
pDriverData = NULL;
pfnIdentify = NULL;
pfnRename = NULL;
pfnCopyFiles = NULL;
}
/************************************************************************/
/* ~GDALDriver() */
/************************************************************************/
GDALDriver::~GDALDriver()
{
if( pfnUnloadDriver != NULL )
pfnUnloadDriver( this );
}
/************************************************************************/
/* GDALDestroyDriver() */
/************************************************************************/
/**
* Destroy a GDALDriver.
*
* This is roughly equivelent to deleting the driver, but is guaranteed
* to take place in the GDAL heap. It is important this that function
* not be called on a driver that is registered with the GDALDriverManager.
*
* @param hDriver the driver to destroy.
*/
void CPL_STDCALL GDALDestroyDriver( GDALDriverH hDriver )
{
VALIDATE_POINTER0( hDriver, "GDALDestroyDriver" );
delete ((GDALDriver *) hDriver);
}
/************************************************************************/
/* Create() */
/************************************************************************/
/**
* Create a new dataset with this driver.
*
* What argument values are legal for particular drivers is driver specific,
* and there is no way to query in advance to establish legal values.
*
* That function will try to validate the creation option list passed to the driver
* with the GDALValidateCreationOptions() method. This check can be disabled
* by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS=NO.
*
* Equivelent of the C function GDALCreate().
*
* @param pszFilename the name of the dataset to create.
* @param nXSize width of created raster in pixels.
* @param nYSize height of created raster in pixels.
* @param nBands number of bands.
* @param eType type of raster.
* @param papszParmList list of driver specific control parameters.
*
* @return NULL on failure, or a new GDALDataset.
*/
GDALDataset * GDALDriver::Create( const char * pszFilename,
int nXSize, int nYSize, int nBands,
GDALDataType eType, char ** papszParmList )
{
CPLLocaleC oLocaleForcer;
/* -------------------------------------------------------------------- */
/* Does this format support creation. */
/* -------------------------------------------------------------------- */
if( pfnCreate == NULL )
{
CPLError( CE_Failure, CPLE_NotSupported,
"GDALDriver::Create() ... no create method implemented"
" for this format.\n" );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Do some rudimentary argument checking. */
/* -------------------------------------------------------------------- */
if( nXSize < 1 || nYSize < 1 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Attempt to create %dx%d dataset is illegal,"
"sizes must be larger than zero.",
nXSize, nYSize );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Make sure we cleanup if there is an existing dataset of this */
/* name. But even if that seems to fail we will continue since */
/* it might just be a corrupt file or something. */
/* -------------------------------------------------------------------- */
QuietDelete( pszFilename );
if (CSLTestBoolean(CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
GDALValidateCreationOptions( this, papszParmList);
/* -------------------------------------------------------------------- */
/* Proceed with creation. */
/* -------------------------------------------------------------------- */
GDALDataset *poDS;
CPLDebug( "GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
GetDescription(), pszFilename, nXSize, nYSize, nBands,
GDALGetDataTypeName( eType ),
papszParmList );
poDS = pfnCreate( pszFilename, nXSize, nYSize, nBands, eType,
papszParmList );
if( poDS != NULL )
{
if( poDS->GetDescription() == NULL
|| strlen(poDS->GetDescription()) == 0 )
poDS->SetDescription( pszFilename );
if( poDS->poDriver == NULL )
poDS->poDriver = this;
}
return poDS;
}
/************************************************************************/
/* GDALCreate() */
/************************************************************************/
/**
* @see GDALDriver::Create()
*/
GDALDatasetH CPL_DLL CPL_STDCALL
GDALCreate( GDALDriverH hDriver, const char * pszFilename,
int nXSize, int nYSize, int nBands, GDALDataType eBandType,
char ** papszOptions )
{
VALIDATE_POINTER1( hDriver, "GDALCreate", NULL );
return( ((GDALDriver *) hDriver)->Create( pszFilename,
nXSize, nYSize, nBands,
eBandType, papszOptions ) );
}
/************************************************************************/
/* CopyBandImageData() */
/* */
/* Local helper function to copy image data from source to */
/* destination band. */
/************************************************************************/
static CPLErr CopyBandImageData( GDALRasterBand *poSrcBand,
GDALRasterBand *poDstBand,
GDALProgressFunc pfnProgress,
void *pProgressData,
double dfProgBase, double dfProgRatio )
{
void *pData;
GDALDataType eType = poDstBand->GetRasterDataType();
int nXSize = poSrcBand->GetXSize();
int nYSize = poSrcBand->GetYSize();
int iLine;
CPLErr eErr = CE_None;
pData = VSIMalloc2(nXSize, GDALGetDataTypeSize(eType) / 8);
if( pData == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"CopyBandImageData(): Out of memory.\n");
eErr = CE_Failure;
}
for( iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )
{
eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
pData, nXSize, 1, eType, 0, 0 );
if( eErr != CE_None )
break;
eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
pData, nXSize, 1, eType, 0, 0 );
if( !pfnProgress( ((iLine+1) / (double) nYSize) * dfProgRatio
+ dfProgBase, NULL, pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
eErr = CE_Failure;
}
}
CPLFree( pData );
return eErr;
}
/************************************************************************/
/* DefaultCopyMasks() */
/************************************************************************/
CPLErr GDALDriver::DefaultCopyMasks( GDALDataset *poSrcDS,
GDALDataset *poDstDS,
int bStrict )
{
CPLErr eErr = CE_None;
/* -------------------------------------------------------------------- */
/* Try to copy mask if it seems appropriate. */
/* -------------------------------------------------------------------- */
for( int iBand = 0;
eErr == CE_None && iBand < poSrcDS->GetRasterCount();
iBand++ )
{
GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand+1 );
int nMaskFlags = poSrcBand->GetMaskFlags();
if( eErr == CE_None
&& !(nMaskFlags & (GMF_ALL_VALID|GMF_PER_DATASET|GMF_ALPHA|GMF_NODATA) ) )
{
eErr = poDstBand->CreateMaskBand( nMaskFlags );
if( eErr == CE_None )
{
eErr = CopyBandImageData(
poSrcBand->GetMaskBand(),
poDstBand->GetMaskBand(),
GDALDummyProgress, NULL, 0.0, 0.0 );
}
else if( !bStrict )
eErr = CE_None;
}
}
/* -------------------------------------------------------------------- */
/* Try to copy a per-dataset mask if we have one. */
/* -------------------------------------------------------------------- */
int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
if( eErr == CE_None
&& !(nMaskFlags & (GMF_ALL_VALID|GMF_ALPHA|GMF_NODATA) )
&& (nMaskFlags & GMF_PER_DATASET) )
{
eErr = poDstDS->CreateMaskBand( nMaskFlags );
if( eErr == CE_None )
{
eErr = CopyBandImageData(
poSrcDS->GetRasterBand(1)->GetMaskBand(),
poDstDS->GetRasterBand(1)->GetMaskBand(),
GDALDummyProgress, NULL, 0.0, 0.0 );
}
else if( !bStrict )
eErr = CE_None;
}
return eErr;
}
/************************************************************************/
/* DefaultCreateCopy() */
/************************************************************************/
GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
GDALDataset * poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
CPLErrorReset();
/* -------------------------------------------------------------------- */
/* Create destination dataset. */
/* -------------------------------------------------------------------- */
GDALDataset *poDstDS;
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
CPLErr eErr = CE_None;
CPLDebug( "GDAL", "Using default GDALDriver::CreateCopy implementation." );
if( !pfnProgress( 0.0, NULL, pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
return NULL;
}
poDstDS = Create( pszFilename, nXSize, nYSize,
poSrcDS->GetRasterCount(), eType, papszOptions );
if( poDstDS == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Try setting the projection and geotransform if it seems */
/* suitable. */
/* -------------------------------------------------------------------- */
double adfGeoTransform[6];
if( eErr == CE_None
&& poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
&& (adfGeoTransform[0] != 0.0
|| adfGeoTransform[1] != 1.0
|| adfGeoTransform[2] != 0.0
|| adfGeoTransform[3] != 0.0
|| adfGeoTransform[4] != 0.0
|| adfGeoTransform[5] != 1.0) )
{
eErr = poDstDS->SetGeoTransform( adfGeoTransform );
if( !bStrict )
eErr = CE_None;
}
if( eErr == CE_None
&& poSrcDS->GetProjectionRef() != NULL
&& strlen(poSrcDS->GetProjectionRef()) > 0 )
{
eErr = poDstDS->SetProjection( poSrcDS->GetProjectionRef() );
if( !bStrict )
eErr = CE_None;
}
/* -------------------------------------------------------------------- */
/* Copy GCPs. */
/* -------------------------------------------------------------------- */
if( poSrcDS->GetGCPCount() > 0 && eErr == CE_None )
{
eErr = poDstDS->SetGCPs( poSrcDS->GetGCPCount(),
poSrcDS->GetGCPs(),
poSrcDS->GetGCPProjection() );
if( !bStrict )
eErr = CE_None;
}
/* -------------------------------------------------------------------- */
/* Copy metadata. */
/* -------------------------------------------------------------------- */
poDstDS->SetMetadata( poSrcDS->GetMetadata() );
/* -------------------------------------------------------------------- */
/* Copy transportable special domain metadata (RPCs). It would */
/* be nice to copy geolocation, but is is pretty fragile. */
/* -------------------------------------------------------------------- */
char **papszMD = poSrcDS->GetMetadata( "RPC" );
if( papszMD )
poDstDS->SetMetadata( papszMD, "RPC" );
/* -------------------------------------------------------------------- */
/* Loop copying bands. */
/* -------------------------------------------------------------------- */
for( int iBand = 0;
eErr == CE_None && iBand < poSrcDS->GetRasterCount();
iBand++ )
{
GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand+1 );
/* -------------------------------------------------------------------- */
/* Do we need to copy a colortable. */
/* -------------------------------------------------------------------- */
GDALColorTable *poCT;
int bSuccess;
double dfValue;
poCT = poSrcBand->GetColorTable();
if( poCT != NULL )
poDstBand->SetColorTable( poCT );
/* -------------------------------------------------------------------- */
/* Do we need to copy other metadata? Most of this is */
/* non-critical, so lets not bother folks if it fails are we */
/* are not in strict mode. */
/* -------------------------------------------------------------------- */
if( !bStrict )
CPLPushErrorHandler( CPLQuietErrorHandler );
if( strlen(poSrcBand->GetDescription()) > 0 )
poDstBand->SetDescription( poSrcBand->GetDescription() );
poDstBand->SetMetadata( poSrcBand->GetMetadata() );
dfValue = poSrcBand->GetOffset( &bSuccess );
if( bSuccess && dfValue != 0.0 )
poDstBand->SetOffset( dfValue );
dfValue = poSrcBand->GetScale( &bSuccess );
if( bSuccess && dfValue != 1.0 )
poDstBand->SetScale( dfValue );
dfValue = poSrcBand->GetNoDataValue( &bSuccess );
if( bSuccess )
poDstBand->SetNoDataValue( dfValue );
if( poSrcBand->GetColorInterpretation() != GCI_Undefined
&& poSrcBand->GetColorInterpretation()
!= poDstBand->GetColorInterpretation() )
poDstBand->SetColorInterpretation(
poSrcBand->GetColorInterpretation() );
char** papszCatNames;
papszCatNames = poSrcBand->GetCategoryNames();
if (0 != papszCatNames)
poDstBand->SetCategoryNames( papszCatNames );
if( !bStrict )
{
CPLPopErrorHandler();
CPLErrorReset();
}
else
eErr = CPLGetLastErrorType();
}
/* -------------------------------------------------------------------- */
/* Copy image data. */
/* -------------------------------------------------------------------- */
if( eErr == CE_None )
eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS,
(GDALDatasetH) poDstDS,
NULL, pfnProgress, pProgressData );
/* -------------------------------------------------------------------- */
/* Should we copy some masks over? */
/* -------------------------------------------------------------------- */
if( eErr == CE_None )
eErr = DefaultCopyMasks( poSrcDS, poDstDS, eErr );
/* -------------------------------------------------------------------- */
/* Try to cleanup the output dataset if the translation failed. */
/* -------------------------------------------------------------------- */
if( eErr != CE_None )
{
delete poDstDS;
Delete( pszFilename );
return NULL;
}
else
CPLErrorReset();
return poDstDS;
}
/************************************************************************/
/* CreateCopy() */
/************************************************************************/
/**
* Create a copy of a dataset.
*
* This method will attempt to create a copy of a raster dataset with the
* indicated filename, and in this drivers format. Band number, size,
* type, projection, geotransform and so forth are all to be copied from
* the provided template dataset.
*
* Note that many sequential write once formats (such as JPEG and PNG) don't
* implement the Create() method but do implement this CreateCopy() method.
* If the driver doesn't implement CreateCopy(), but does implement Create()
* then the default CreateCopy() mechanism built on calling Create() will
* be used.
*
* It is intended that CreateCopy() will often be used with a source dataset
* which is a virtual dataset allowing configuration of band types, and
* other information without actually duplicating raster data (see the VRT driver).
* This is what is done by the gdal_translate utility for example.
*
* That function will try to validate the creation option list passed to the driver
* with the GDALValidateCreationOptions() method. This check can be disabled
* by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS=NO.
*
* @param pszFilename the name for the new dataset.
* @param poSrcDS the dataset being duplicated.
* @param bStrict TRUE if the copy must be strictly equivelent, or more
* normally FALSE indicating that the copy may adapt as needed for the
* output format.
* @param papszOptions additional format dependent options controlling
* creation of the output file.
* @param pfnProgress a function to be used to report progress of the copy.
* @param pProgressData application data passed into progress function.
*
* @return a pointer to the newly created dataset (may be read-only access).
*/
GDALDataset *GDALDriver::CreateCopy( const char * pszFilename,
GDALDataset * poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
CPLLocaleC oLocaleForcer;
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* Make sure we cleanup if there is an existing dataset of this */
/* name. But even if that seems to fail we will continue since */
/* it might just be a corrupt file or something. */
/* -------------------------------------------------------------------- */
QuietDelete( pszFilename );
if (CSLTestBoolean(CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
GDALValidateCreationOptions( this, papszOptions);
/* -------------------------------------------------------------------- */
/* If the format provides a CreateCopy() method use that, */
/* otherwise fallback to the internal implementation using the */
/* Create() method. */
/* -------------------------------------------------------------------- */
if( pfnCreateCopy != NULL )
{
GDALDataset *poDstDS;
poDstDS = pfnCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
pfnProgress, pProgressData );
if( poDstDS != NULL )
{
if( poDstDS->GetDescription() == NULL
|| strlen(poDstDS->GetDescription()) == 0 )
poDstDS->SetDescription( pszFilename );
if( poDstDS->poDriver == NULL )
poDstDS->poDriver = this;
}
return poDstDS;
}
else
return DefaultCreateCopy( pszFilename, poSrcDS, bStrict,
papszOptions, pfnProgress, pProgressData );
}
/************************************************************************/
/* GDALCreateCopy() */
/************************************************************************/
/**
* @see GDALDriver::CreateCopy()
*/
GDALDatasetH CPL_STDCALL GDALCreateCopy( GDALDriverH hDriver,
const char * pszFilename,
GDALDatasetH hSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
VALIDATE_POINTER1( hDriver, "GDALCreateCopy", NULL );
VALIDATE_POINTER1( hSrcDS, "GDALCreateCopy", NULL );
return (GDALDatasetH) ((GDALDriver *) hDriver)->
CreateCopy( pszFilename, (GDALDataset *) hSrcDS, bStrict, papszOptions,
pfnProgress, pProgressData );
}
/************************************************************************/
/* QuietDelete() */
/************************************************************************/
/**
* Delete dataset if found.
*
* This is a helper method primarily used by Create() and
* CreateCopy() to predelete any dataset of the name soon to be
* created. It will attempt to delete the named dataset if
* one is found, otherwise it does nothing. An error is only
* returned if the dataset is found but the delete fails.
*
* This is a static method and it doesn't matter what driver instance
* it is invoked on. It will attempt to discover the correct driver
* using Identify().
*
* @param pszName the dataset name to try and delete.
* @return CE_None if the dataset does not exist, or is deleted without issues.
*/
CPLErr GDALDriver::QuietDelete( const char *pszName )
{
GDALDriver *poDriver = (GDALDriver*) GDALIdentifyDriver( pszName, NULL );
if( poDriver == NULL )
return CE_None;
CPLDebug( "GDAL", "QuietDelete(%s) invoking Delete()", pszName );
return poDriver->Delete( pszName );
}
/************************************************************************/
/* Delete() */
/************************************************************************/
/**
* Delete named dataset.
*
* The driver will attempt to delete the named dataset in a driver specific
* fashion. Full featured drivers will delete all associated files,
* database objects, or whatever is appropriate. The default behaviour when
* no driver specific behaviour is provided is to attempt to delete the
* passed name as a single file.
*
* It is unwise to have open dataset handles on this dataset when it is
* deleted.
*
* Equivelent of the C function GDALDeleteDataset().
*
* @param pszFilename name of dataset to delete.
*
* @return CE_None on success, or CE_Failure if the operation fails.
*/
CPLErr GDALDriver::Delete( const char * pszFilename )
{
if( pfnDelete != NULL )
return pfnDelete( pszFilename );
/* -------------------------------------------------------------------- */
/* Collect file list. */
/* -------------------------------------------------------------------- */
GDALDatasetH hDS = (GDALDataset *) GDALOpen(pszFilename,GA_ReadOnly);
if( hDS == NULL )
{
if( CPLGetLastErrorNo() == 0 )
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to open %s to obtain file list.", pszFilename );
return CE_Failure;
}
char **papszFileList = GDALGetFileList( hDS );
GDALClose( hDS );
if( CSLCount( papszFileList ) == 0 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"Unable to determine files associated with %s,\n"
"delete fails.", pszFilename );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Delete all files. */
/* -------------------------------------------------------------------- */
int i;
for( i = 0; papszFileList[i] != NULL; i++ )
{
if( VSIUnlink( papszFileList[i] ) != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Deleting %s failed:\n%s",
papszFileList[i],
VSIStrerror(errno) );
CSLDestroy( papszFileList );
return CE_Failure;
}
}
CSLDestroy( papszFileList );
return CE_None;
}
/************************************************************************/
/* GDALDeleteDataset() */
/************************************************************************/
/**
* @see GDALDriver::Delete()
*/
CPLErr CPL_STDCALL GDALDeleteDataset( GDALDriverH hDriver, const char * pszFilename )
{
if( hDriver == NULL )
hDriver = GDALIdentifyDriver( pszFilename, NULL );
if( hDriver == NULL )
{
CPLError( CE_Failure, CPLE_AppDefined,
"No identifiable driver for %s.",
pszFilename );
return CE_Failure;
}
return ((GDALDriver *) hDriver)->Delete( pszFilename );
}
/************************************************************************/
/* Rename() */
/************************************************************************/
/**
* Rename a dataset.
*
* Rename a dataset. This may including moving the dataset to a new directory
* or even a new filesystem.
*
* It is unwise to have open dataset handles on this dataset when it is
* being renamed.
*
* Equivelent of the C function GDALRenameDataset().
*
* @param pszNewName new name for the dataset.
* @param pszOldName old name for the dataset.
*
* @return CE_None on success, or CE_Failure if the operation fails.
*/
CPLErr GDALDriver::Rename( const char * pszNewName, const char *pszOldName )
{
if( pfnRename != NULL )
return pfnRename( pszNewName, pszOldName );
/* -------------------------------------------------------------------- */
/* Collect file list. */
/* -------------------------------------------------------------------- */
GDALDatasetH hDS = (GDALDataset *) GDALOpen(pszOldName,GA_ReadOnly);
if( hDS == NULL )
{
if( CPLGetLastErrorNo() == 0 )
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to open %s to obtain file list.", pszOldName );
return CE_Failure;
}
char **papszFileList = GDALGetFileList( hDS );
GDALClose( hDS );
if( CSLCount( papszFileList ) == 0 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"Unable to determine files associated with %s,\n"
"rename fails.", pszOldName );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Produce a list of new filenames that correspond to the old */
/* names. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
int i;
char **papszNewFileList =
CPLCorrespondingPaths( pszOldName, pszNewName, papszFileList );
if( papszNewFileList == NULL )
return CE_Failure;
for( i = 0; papszFileList[i] != NULL; i++ )
{
if( CPLMoveFile( papszNewFileList[i], papszFileList[i] ) != 0 )
{
eErr = CE_Failure;
// Try to put the ones we moved back.
for( --i; i >= 0; i-- )
CPLMoveFile( papszFileList[i], papszNewFileList[i] );
break;
}
}
CSLDestroy( papszNewFileList );
CSLDestroy( papszFileList );
return eErr;
}
/************************************************************************/
/* GDALRenameDataset() */
/************************************************************************/
/**
* @see GDALDriver::Rename()
*/
CPLErr CPL_STDCALL GDALRenameDataset( GDALDriverH hDriver,
const char * pszNewName,
const char * pszOldName )
{
if( hDriver == NULL )
hDriver = GDALIdentifyDriver( pszOldName, NULL );
if( hDriver == NULL )
{
CPLError( CE_Failure, CPLE_AppDefined,
"No identifiable driver for %s.",
pszOldName );
return CE_Failure;
}
return ((GDALDriver *) hDriver)->Rename( pszNewName, pszOldName );
}
/************************************************************************/
/* CopyFiles() */
/************************************************************************/
/**
* Copy the files of a dataset.
*
* Copy all the files associated with a dataset.
*
* Equivelent of the C function GDALCopyDatasetFiles().
*
* @param pszNewName new name for the dataset.
* @param pszOldName old name for the dataset.
*
* @return CE_None on success, or CE_Failure if the operation fails.
*/
CPLErr GDALDriver::CopyFiles( const char * pszNewName, const char *pszOldName )
{
if( pfnRename != NULL )
return pfnRename( pszNewName, pszOldName );
/* -------------------------------------------------------------------- */
/* Collect file list. */
/* -------------------------------------------------------------------- */
GDALDatasetH hDS = (GDALDataset *) GDALOpen(pszOldName,GA_ReadOnly);
if( hDS == NULL )
{
if( CPLGetLastErrorNo() == 0 )
CPLError( CE_Failure, CPLE_OpenFailed,
"Unable to open %s to obtain file list.", pszOldName );
return CE_Failure;
}
char **papszFileList = GDALGetFileList( hDS );
GDALClose( hDS );
if( CSLCount( papszFileList ) == 0 )
{
CPLError( CE_Failure, CPLE_NotSupported,
"Unable to determine files associated with %s,\n"
"rename fails.", pszOldName );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Produce a list of new filenames that correspond to the old */
/* names. */
/* -------------------------------------------------------------------- */
CPLErr eErr = CE_None;
int i;
char **papszNewFileList =
CPLCorrespondingPaths( pszOldName, pszNewName, papszFileList );
if( papszNewFileList == NULL )
return CE_Failure;
for( i = 0; papszFileList[i] != NULL; i++ )
{
if( CPLCopyFile( papszNewFileList[i], papszFileList[i] ) != 0 )
{
eErr = CE_Failure;
// Try to put the ones we moved back.
for( --i; i >= 0; i-- )
VSIUnlink( papszNewFileList[i] );
break;
}
}
CSLDestroy( papszNewFileList );
CSLDestroy( papszFileList );
return eErr;
}
/************************************************************************/
/* GDALCopyDatasetFiles() */
/************************************************************************/
/**
* @see GDALDriver::CopyFiles()
*/
CPLErr CPL_STDCALL GDALCopyDatasetFiles( GDALDriverH hDriver,
const char * pszNewName,
const char * pszOldName )
{
if( hDriver == NULL )
hDriver = GDALIdentifyDriver( pszOldName, NULL );
if( hDriver == NULL )
{
CPLError( CE_Failure, CPLE_AppDefined,
"No identifiable driver for %s.",
pszOldName );
return CE_Failure;
}
return ((GDALDriver *) hDriver)->CopyFiles( pszNewName, pszOldName );
}
/************************************************************************/
/* GDALGetDriverShortName() */
/************************************************************************/
/**
* Return the short name of a driver
*
* Return the short name of a the driver. This is the string that can be
* passed to the GDALGetDriverByName() function.
*
* For the GeoTIFF driver, this is "GTiff"
*
* @param hDriver the handle of the driver
* @return the short name of the driver. The
* returned string should not be freed and is owned by the driver.
*/
const char * CPL_STDCALL GDALGetDriverShortName( GDALDriverH hDriver )
{
VALIDATE_POINTER1( hDriver, "GDALGetDriverShortName", NULL );
return ((GDALDriver *) hDriver)->GetDescription();
}
/************************************************************************/
/* GDALGetDriverLongName() */
/************************************************************************/
/**
* Return the long name of a driver
*
* Return the long name of a the driver.
*
* For the GeoTIFF driver, this is "GeoTIFF"
*
* @param hDriver the handle of the driver
* @return the long name of the driver or empty string. The
* returned string should not be freed and is owned by the driver.
*/
const char * CPL_STDCALL GDALGetDriverLongName( GDALDriverH hDriver )
{
VALIDATE_POINTER1( hDriver, "GDALGetDriverLongName", NULL );
const char *pszLongName =
((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_LONGNAME );
if( pszLongName == NULL )
return "";
else
return pszLongName;
}
/************************************************************************/
/* GDALGetDriverHelpTopic() */
/************************************************************************/
/**
* Return the URL to the help that describes the driver
*
* Return the URL to the help that describes the driver. That URL is
* relative to the GDAL documentation directory.
*
* For the GeoTIFF driver, this is "frmt_gtiff.html"
*
* @param hDriver the handle of the driver
* @return the URL to the help that describes the driver or NULL. The
* returned string should not be freed and is owned by the driver.
*/
const char * CPL_STDCALL GDALGetDriverHelpTopic( GDALDriverH hDriver )
{
VALIDATE_POINTER1( hDriver, "GDALGetDriverHelpTopic", NULL );
return ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_HELPTOPIC );
}
/************************************************************************/
/* GDALGetDriverCreationOptionList() */
/************************************************************************/
/**
* Return the list of creation options of the driver
*
* Return the list of creation options of the driver used by Create() and
* CreateCopy() as an XML string
*
* @param hDriver the handle of the driver
* @return an XML string that describes the list of creation options or
* empty string. The returned string should not be freed and is
* owned by the driver.
*/
const char * CPL_STDCALL GDALGetDriverCreationOptionList( GDALDriverH hDriver )
{
VALIDATE_POINTER1( hDriver, "GDALGetDriverCreationOptionList", NULL );
const char *pszOptionList =
((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST );
if( pszOptionList == NULL )
return "";
else
return pszOptionList;
}
/************************************************************************/
/* GDALValidateCreationOptions() */
/************************************************************************/
/**
* Validate the list of creation options that are handled by a driver
*
* This is a helper method primarily used by Create() and
* CreateCopy() to validate that the passed in list of creation options
* is compatible with the GDAL_DMD_CREATIONOPTIONLIST metadata item defined
* by some drivers. @see GDALGetDriverCreationOptionList()
*
* If the GDAL_DMD_CREATIONOPTIONLIST metadata item is not defined, this
* function will return TRUE. Otherwise it will check that the keys and values
* in the list of creation options are compatible with the capabilities declared
* by the GDAL_DMD_CREATIONOPTIONLIST metadata item. In case of incompatibility
* a (non fatal) warning will be emited and FALSE will be returned.
*
* @param hDriver the handle of the driver with whom the lists of creation option
* must be validated
* @param papszCreationOptions the list of creation options. An array of strings,
* whose last element is a NULL pointer
* @return TRUE if the list of creation options is compatible with the Create()
* and CreateCopy() method of the driver, FALSE otherwise.
*/
int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
char** papszCreationOptions)
{
int bRet = TRUE;
VALIDATE_POINTER1( hDriver, "GDALValidateCreationOptions", FALSE );
const char *pszOptionList =
((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST );
if( papszCreationOptions == NULL || *papszCreationOptions == NULL)
return TRUE;
if( pszOptionList == NULL )
return TRUE;
CPLXMLNode* psNode = CPLParseXMLString(pszOptionList);
if (psNode == NULL)
{
CPLError(CE_Warning, CPLE_AppDefined,
"Could not parse creation option list of driver %s. Assuming creation options are valid.",
((GDALDriver *) hDriver)->GetDescription());
return TRUE;
}
while(*papszCreationOptions)
{
char* pszKey = NULL;
const char* pszValue = CPLParseNameValue(*papszCreationOptions, &pszKey);
if (pszKey == NULL)
{
CPLError(CE_Warning, CPLE_NotSupported,
"Creation option '%s' is not formatted with the key=value format",
*papszCreationOptions);
bRet = FALSE;
papszCreationOptions ++;
continue;
}
CPLXMLNode* psChildNode = psNode->psChild;
while(psChildNode)
{
if (EQUAL(psChildNode->pszValue, "OPTION"))
{
const char* pszOptionName = CPLGetXMLValue(psChildNode, "name", "");
/* For option names terminated by wildcard (NITF BLOCKA option names for example) */
if (strlen(pszOptionName) > 0 &&
pszOptionName[strlen(pszOptionName) - 1] == '*' &&
EQUALN(pszOptionName, pszKey, strlen(pszOptionName) - 1))
{
break;
}
if (EQUAL(pszOptionName, pszKey) ||
EQUAL(CPLGetXMLValue(psChildNode, "alias", ""), pszKey))
{
break;
}
}
psChildNode = psChildNode->psNext;
}
if (psChildNode == NULL)
{
CPLError(CE_Warning, CPLE_NotSupported,
"Driver %s does not support %s creation option",
((GDALDriver *) hDriver)->GetDescription(),
pszKey);
CPLFree(pszKey);
bRet = FALSE;
papszCreationOptions ++;
continue;
}
const char* pszType = CPLGetXMLValue(psChildNode, "type", NULL);
if (pszType != NULL)
{
if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
{
const char* pszValueIter = pszValue;
while (*pszValueIter)
{
if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
*pszValueIter == '+' || *pszValueIter == '-'))
{
CPLError(CE_Warning, CPLE_NotSupported,
"'%s' is an unexpected value for %s creation option of type int.",
pszValue, pszKey);
bRet = FALSE;
break;
}
pszValueIter++;
}
}
else if (EQUAL(pszType, "UNSIGNED INT"))
{
const char* pszValueIter = pszValue;
while (*pszValueIter)
{
if (!((*pszValueIter >= '0' && *pszValueIter <= '9') ||
*pszValueIter == '+'))
{
CPLError(CE_Warning, CPLE_NotSupported,
"'%s' is an unexpected value for %s creation option of type unsigned int.",
pszValue, pszKey);
bRet = FALSE;
break;
}
pszValueIter++;
}
}
else if (EQUAL(pszType, "FLOAT"))
{
char* endPtr = NULL;
CPLStrtod(pszValue, &endPtr);
if ( !(endPtr == NULL || *endPtr == '\0') )
{
CPLError(CE_Warning, CPLE_NotSupported,
"'%s' is an unexpected value for %s creation option of type float.",
pszValue, pszKey);
bRet = FALSE;
}
}
else if (EQUAL(pszType, "BOOLEAN"))
{
if (!(EQUAL(pszValue, "ON") || EQUAL(pszValue, "TRUE") || EQUAL(pszValue, "YES") ||
EQUAL(pszValue, "OFF") || EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
{
CPLError(CE_Warning, CPLE_NotSupported,
"'%s' is an unexpected value for %s creation option of type boolean.",
pszValue, pszKey);
bRet = FALSE;
}
}
else if (EQUAL(pszType, "STRING-SELECT"))
{
int bMatchFound = FALSE;
CPLXMLNode* psStringSelect = psChildNode->psChild;
while(psStringSelect)
{
CPLXMLNode* psOptionNode = psStringSelect->psChild;
if (psOptionNode && EQUAL(psStringSelect->pszValue, "Value"))
{
if (EQUAL(psOptionNode->pszValue, pszValue))
{
bMatchFound = TRUE;
break;
}
}
psStringSelect = psStringSelect->psNext;
}
if (!bMatchFound)
{
CPLError(CE_Warning, CPLE_NotSupported,
"'%s' is an unexpected value for %s creation option of type string-select.",
pszValue, pszKey);
bRet = FALSE;
}
}
else if (EQUAL(pszType, "STRING"))
{
const char* pszMaxSize = CPLGetXMLValue(psChildNode, "maxsize", NULL);
if (pszMaxSize != NULL)
{
if ((int)strlen(pszValue) > atoi(pszMaxSize))
{
CPLError(CE_Warning, CPLE_NotSupported,
"'%s' is of size %d, whereas maximum size for %s creation option is %d.",
pszValue, (int)strlen(pszValue), pszKey, atoi(pszMaxSize));
bRet = FALSE;
}
}
}
else
{
/* Driver error */
CPLError(CE_Warning, CPLE_NotSupported,
"Driver %s : type '%s' for %s creation option is not recognized.",
((GDALDriver *) hDriver)->GetDescription(),
pszType,
pszKey);
}
}
else
{
/* Driver error */
CPLError(CE_Warning, CPLE_NotSupported,
"Driver %s : no type for %s creation option.",
((GDALDriver *) hDriver)->GetDescription(),
pszKey);
}
CPLFree(pszKey);
papszCreationOptions++;
}
CPLDestroyXMLNode(psNode);
return bRet;
}
/************************************************************************/
/* GDALIdentifyDriver() */
/************************************************************************/
/**
* Identify the driver that can open a raster file.
*
* This function will try to identify the driver that can open the passed file
* name by invoking the Identify method of each registered GDALDriver in turn.
* The first driver that successful identifies the file name will be returned.
* If all drivers fail then NULL is returned.
*
* In order to reduce the need for such searches touch the operating system
* file system machinery, it is possible to give an optional list of files.
* This is the list of all files at the same level in the file system as the
* target file, including the target file. The filenames will not include any
* path components, are an essentially just the output of CPLReadDir() on the
* parent directory. If the target object does not have filesystem semantics
* then the file list should be NULL.
*
* @param pszFilename the name of the file to access. In the case of
* exotic drivers this may not refer to a physical file, but instead contain
* information for the driver on how to access a dataset.
*
* @param papszFileList an array of strings, whose last element is the NULL pointer.
* These strings are filenames that are auxiliary to the main filename. The passed
* value may be NULL.
*
* @return A GDALDriverH handle or NULL on failure. For C++ applications
* this handle can be cast to a GDALDriver *.
*/
GDALDriverH CPL_STDCALL
GDALIdentifyDriver( const char * pszFilename,
char **papszFileList )
{
int iDriver;
GDALDriverManager *poDM = GetGDALDriverManager();
GDALOpenInfo oOpenInfo( pszFilename, GA_ReadOnly, papszFileList );
CPLLocaleC oLocaleForcer;
CPLErrorReset();
CPLAssert( NULL != poDM );
for( iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++ )
{
GDALDriver *poDriver = poDM->GetDriver( iDriver );
GDALDataset *poDS;
VALIDATE_POINTER1( poDriver, "GDALIdentifyDriver", NULL );
if( poDriver->pfnIdentify != NULL )
{
if( poDriver->pfnIdentify( &oOpenInfo ) )
return (GDALDriverH) poDriver;
}
else if( poDriver->pfnOpen != NULL )
{
poDS = poDriver->pfnOpen( &oOpenInfo );
if( poDS != NULL )
{
delete poDS;
return (GDALDriverH) poDriver;
}
if( CPLGetLastErrorNo() != 0 )
return NULL;
}
}
return NULL;
}