/****************************************************************************** * $Id: gdaldataset.cpp 11489 2007-05-11 19:27:48Z warmerdam $ * * Project: GDAL Core * Purpose: Base class for raster file formats. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1998, 2003, 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" #include "cpl_string.h" #include "cpl_multiproc.h" CPL_CVSID("$Id: gdaldataset.cpp 11489 2007-05-11 19:27:48Z warmerdam $"); static volatile int nGDALDatasetCount = 0; static GDALDataset ** volatile papoGDALDatasetList = NULL; static void *hDLMutex = NULL; /************************************************************************/ /* ==================================================================== */ /* GDALDataset */ /* ==================================================================== */ /************************************************************************/ /** * \class GDALDataset "gdal_priv.h" * * A dataset encapsulating one or more raster bands. Details are * further discussed in the GDAL * Data Model. * * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file, * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new * dataset. */ /************************************************************************/ /* GDALDataset() */ /************************************************************************/ GDALDataset::GDALDataset() { poDriver = NULL; eAccess = GA_ReadOnly; nRasterXSize = 512; nRasterYSize = 512; nBands = 0; papoBands = NULL; nRefCount = 1; bShared = FALSE; /* -------------------------------------------------------------------- */ /* Add this dataset to the open dataset list. */ /* -------------------------------------------------------------------- */ { CPLMutexHolderD( &hDLMutex ); nGDALDatasetCount++; papoGDALDatasetList = (GDALDataset ** volatile) CPLRealloc( papoGDALDatasetList, sizeof(void *)*nGDALDatasetCount); papoGDALDatasetList[nGDALDatasetCount-1] = this; } /* -------------------------------------------------------------------- */ /* Set forced caching flag. */ /* -------------------------------------------------------------------- */ bForceCachedIO = CSLTestBoolean( CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") ); } /************************************************************************/ /* ~GDALDataset() */ /************************************************************************/ /** * Destroy an open GDALDataset. * * This is the accepted method of closing a GDAL dataset and deallocating * all resources associated with it. * * Equivelent of the C callable GDALClose(). Except that GDALClose() first * decrements the reference count, and then closes only if it has dropped to * zero. */ GDALDataset::~GDALDataset() { int i; // we don't want to report destruction of datasets that // were never really open. if( nBands != 0 || !EQUAL(GetDescription(),"") ) CPLDebug( "GDAL", "GDALClose(%s)", GetDescription() ); /* -------------------------------------------------------------------- */ /* Remove dataset from the "open" dataset list. */ /* -------------------------------------------------------------------- */ { CPLMutexHolderD( &hDLMutex ); for( i = 0; i < nGDALDatasetCount; i++ ) { if( papoGDALDatasetList[i] == this ) { papoGDALDatasetList[i] = papoGDALDatasetList[nGDALDatasetCount-1]; nGDALDatasetCount--; if( nGDALDatasetCount == 0 ) { CPLFree( papoGDALDatasetList ); papoGDALDatasetList = NULL; } break; } } } /* -------------------------------------------------------------------- */ /* Destroy the raster bands if they exist. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nBands && papoBands != NULL; i++ ) { if( papoBands[i] != NULL ) delete papoBands[i]; } CPLFree( papoBands ); } /************************************************************************/ /* FlushCache() */ /************************************************************************/ /** * Flush all write cached data to disk. * * Any raster (or other GDAL) data written via GDAL calls, but buffered * internally will be written to disk. * * This method is the same as the C function GDALFlushCache(). */ void GDALDataset::FlushCache() { int i; // This sometimes happens if a dataset is destroyed before completely // built. if( papoBands == NULL ) return; for( i = 0; i < nBands; i++ ) { if( papoBands[i] != NULL ) papoBands[i]->FlushCache(); } } /************************************************************************/ /* GDALFlushCache() */ /************************************************************************/ /** * @see GDALDataset::FlushCache(). */ void CPL_STDCALL GDALFlushCache( GDALDatasetH hDS ) { ((GDALDataset *) hDS)->FlushCache(); } /************************************************************************/ /* BlockBasedFlushCache() */ /* */ /* This helper method can be called by the */ /* GDALDataset::FlushCache() for particular drivers to ensure */ /* that buffers will be flushed in a manner suitable for pixel */ /* interleaved (by block) IO. That is, if all the bands have */ /* the same size blocks then a given block will be flushed for */ /* all bands before proceeding to the next block. */ /************************************************************************/ void GDALDataset::BlockBasedFlushCache() { GDALRasterBand *poBand1; int nBlockXSize, nBlockYSize, iBand; poBand1 = GetRasterBand( 1 ); if( poBand1 == NULL ) { GDALDataset::FlushCache(); return; } poBand1->GetBlockSize( &nBlockXSize, &nBlockYSize ); /* -------------------------------------------------------------------- */ /* Verify that all bands match. */ /* -------------------------------------------------------------------- */ for( iBand = 1; iBand < nBands; iBand++ ) { int nThisBlockXSize, nThisBlockYSize; GDALRasterBand *poBand = GetRasterBand( iBand+1 ); poBand->GetBlockSize( &nThisBlockXSize, &nThisBlockYSize ); if( nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize ) { GDALDataset::FlushCache(); return; } } /* -------------------------------------------------------------------- */ /* Now flush writable data. */ /* -------------------------------------------------------------------- */ for( int iY = 0; iY < poBand1->nBlocksPerColumn; iY++ ) { for( int iX = 0; iX < poBand1->nBlocksPerRow; iX++ ) { for( iBand = 0; iBand < nBands; iBand++ ) { GDALRasterBand *poBand = GetRasterBand( iBand+1 ); if( poBand->papoBlocks[iX + iY*poBand1->nBlocksPerRow] != NULL) { CPLErr eErr; eErr = poBand->FlushBlock( iX, iY ); if( eErr != CE_None ) return; } } } } } /************************************************************************/ /* RasterInitialize() */ /* */ /* Initialize raster size */ /************************************************************************/ void GDALDataset::RasterInitialize( int nXSize, int nYSize ) { CPLAssert( nXSize > 0 && nYSize > 0 ); nRasterXSize = nXSize; nRasterYSize = nYSize; } /************************************************************************/ /* AddBand() */ /************************************************************************/ /** * Add a band to a dataset. * * This method will add a new band to the dataset if the underlying format * supports this action. Most formats do not. * * Note that the new GDALRasterBand is not returned. It may be fetched * after successful completion of the method by calling * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()-1) as the newest * band will always be the last band. * * @param eType the data type of the pixels in the new band. * * @param papszOptions a list of NAME=VALUE option strings. The supported * options are format specific. NULL may be passed by default. * * @return CE_None on success or CE_Failure on failure. */ CPLErr GDALDataset::AddBand( GDALDataType eType, char ** papszOptions ) { (void) eType; (void) papszOptions; CPLError( CE_Failure, CPLE_NotSupported, "Dataset does not support the AddBand() method." ); return CE_Failure; } /************************************************************************/ /* GDALAddBand() */ /************************************************************************/ /** * @see GDALDataset::AddBand(). */ CPLErr CPL_STDCALL GDALAddBand( GDALDatasetH hDataset, GDALDataType eType, char **papszOptions ) { return ((GDALDataset *) hDataset)->AddBand( eType, papszOptions ); } /************************************************************************/ /* SetBand() */ /* */ /* Set a band in the band array, updating the band count, and */ /* array size appropriately. */ /************************************************************************/ void GDALDataset::SetBand( int nNewBand, GDALRasterBand * poBand ) { /* -------------------------------------------------------------------- */ /* Do we need to grow the bands list? */ /* -------------------------------------------------------------------- */ if( nBands < nNewBand || papoBands == NULL ) { int i; if( papoBands == NULL ) papoBands = (GDALRasterBand **) VSICalloc(sizeof(GDALRasterBand*), MAX(nNewBand,nBands)); else papoBands = (GDALRasterBand **) VSIRealloc(papoBands, sizeof(GDALRasterBand*) * MAX(nNewBand,nBands)); for( i = nBands; i < nNewBand; i++ ) papoBands[i] = NULL; nBands = MAX(nBands,nNewBand); } /* -------------------------------------------------------------------- */ /* Set the band. Resetting the band is currently not permitted. */ /* -------------------------------------------------------------------- */ CPLAssert( papoBands[nNewBand-1] == NULL ); papoBands[nNewBand-1] = poBand; /* -------------------------------------------------------------------- */ /* Set back reference information on the raster band. Note */ /* that the GDALDataset is a friend of the GDALRasterBand */ /* specifically to allow this. */ /* -------------------------------------------------------------------- */ poBand->nBand = nNewBand; poBand->poDS = this; poBand->nRasterXSize = nRasterXSize; poBand->nRasterYSize = nRasterYSize; poBand->eAccess = eAccess; /* default access to be same as dataset */ } /************************************************************************/ /* GetRasterXSize() */ /************************************************************************/ /** Fetch raster width in pixels. Equivelent of the C function GDALGetRasterXSize(). @return the width in pixels of raster bands in this GDALDataset. */ int GDALDataset::GetRasterXSize() { return nRasterXSize; } /************************************************************************/ /* GDALGetRasterXSize() */ /************************************************************************/ /** * @see GDALDataset::GetRasterXSize(). */ int CPL_STDCALL GDALGetRasterXSize( GDALDatasetH hDataset ) { return ((GDALDataset *) hDataset)->GetRasterXSize(); } /************************************************************************/ /* GetRasterYSize() */ /************************************************************************/ /** Fetch raster height in pixels. Equivelent of the C function GDALGetRasterYSize(). @return the height in pixels of raster bands in this GDALDataset. */ int GDALDataset::GetRasterYSize() { return nRasterYSize; } /************************************************************************/ /* GDALGetRasterYSize() */ /************************************************************************/ /** * @see GDALDataset::GetRasterYSize(). */ int CPL_STDCALL GDALGetRasterYSize( GDALDatasetH hDataset ) { return ((GDALDataset *) hDataset)->GetRasterYSize(); } /************************************************************************/ /* GetRasterBand() */ /************************************************************************/ /** Fetch a band object for a dataset. Equivelent of the C function GDALGetRasterBand(). @param nBandId the index number of the band to fetch, from 1 to GetRasterCount(). @return the height in pixels of raster bands in this GDALDataset. */ GDALRasterBand * GDALDataset::GetRasterBand( int nBandId ) { if( nBandId < 1 || nBandId > nBands ) { CPLError( CE_Failure, CPLE_IllegalArg, "GDALDataset::GetRasterBand(%d) - Illegal band #\n", nBandId ); return NULL; } else return( papoBands[nBandId-1] ); } /************************************************************************/ /* GDALGetRasterBand() */ /************************************************************************/ /** * @see GDALDataset::GetRasterBand(). */ GDALRasterBandH CPL_STDCALL GDALGetRasterBand( GDALDatasetH hDS, int nBandId ) { return( (GDALRasterBandH) ((GDALDataset *) hDS)->GetRasterBand(nBandId) ); } /************************************************************************/ /* GetRasterCount() */ /************************************************************************/ /** * Fetch the number of raster bands on this dataset. * * Same as the C function GDALGetRasterCount(). * * @return the number of raster bands. */ int GDALDataset::GetRasterCount() { return( nBands ); } /************************************************************************/ /* GDALGetRasterCount() */ /************************************************************************/ /** * @see GDALDataset::GetRasterCount(). */ int CPL_STDCALL GDALGetRasterCount( GDALDatasetH hDS ) { return( ((GDALDataset *) hDS)->GetRasterCount() ); } /************************************************************************/ /* GetProjectionRef() */ /************************************************************************/ /** * Fetch the projection definition string for this dataset. * * Same as the C function GDALGetProjectionRef(). * * The returned string defines the projection coordinate system of the * image in OpenGIS WKT format. It should be suitable for use with the * OGRSpatialReference class. * * When a projection definition is not available an empty (but not NULL) * string is returned. * * @return a pointer to an internal projection reference string. It should * not be altered, freed or expected to last for long. * * @see http://www.gdal.org/ogr/osr_tutorial.html */ const char *GDALDataset::GetProjectionRef() { return( "" ); } /************************************************************************/ /* GDALGetProjectionRef() */ /************************************************************************/ /** * @see GDALDataset::GetProjectionRef() */ const char * CPL_STDCALL GDALGetProjectionRef( GDALDatasetH hDS ) { return( ((GDALDataset *) hDS)->GetProjectionRef() ); } /************************************************************************/ /* SetProjection() */ /************************************************************************/ /** * Set the projection reference string for this dataset. * * The string should be in OGC WKT or PROJ.4 format. An error may occur * because of incorrectly specified projection strings, because the dataset * is not writable, or because the dataset does not support the indicated * projection. Many formats do not support writing projections. * * This method is the same as the C GDALSetProjection() function. * * @param pszProjection projection reference string. * * @return CE_Failure if an error occurs, otherwise CE_None. */ CPLErr GDALDataset::SetProjection( const char * ) { if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) ) CPLError( CE_Failure, CPLE_NotSupported, "Dataset does not support the SetProjection() method." ); return CE_Failure; } /************************************************************************/ /* GDALSetProjection() */ /************************************************************************/ /** * @see GDALDataset::SetProjection() */ CPLErr CPL_STDCALL GDALSetProjection( GDALDatasetH hDS, const char * pszProjection ) { return( ((GDALDataset *) hDS)->SetProjection(pszProjection) ); } /************************************************************************/ /* GetGeoTransform() */ /************************************************************************/ /** * Fetch the affine transformation coefficients. * * Fetches the coefficients for transforming between pixel/line (P,L) raster * space, and projection coordinates (Xp,Yp) space. * * \code * Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2]; * Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5]; * \endcode * * In a north up image, padfTransform[1] is the pixel width, and * padfTransform[5] is the pixel height. The upper left corner of the * upper left pixel is at position (padfTransform[0],padfTransform[3]). * * The default transform is (0,1,0,0,0,1) and should be returned even when * a CE_Failure error is returned, such as for formats that don't support * transformation to projection coordinates. * * NOTE: GetGeoTransform() isn't expressive enough to handle the variety of * OGC Grid Coverages pixel/line to projection transformation schemes. * Eventually this method will be depreciated in favour of a more general * scheme. * * This method does the same thing as the C GDALGetGeoTransform() function. * * @param padfTransform an existing six double buffer into which the * transformation will be placed. * * @return CE_None on success, or CE_Failure if no transform can be fetched. */ CPLErr GDALDataset::GetGeoTransform( double * padfTransform ) { CPLAssert( padfTransform != NULL ); padfTransform[0] = 0.0; /* X Origin (top left corner) */ padfTransform[1] = 1.0; /* X Pixel size */ padfTransform[2] = 0.0; padfTransform[3] = 0.0; /* Y Origin (top left corner) */ padfTransform[4] = 0.0; padfTransform[5] = 1.0; /* Y Pixel Size */ return( CE_Failure ); } /************************************************************************/ /* GDALGetGeoTransform() */ /************************************************************************/ /** * @see GDALDataset::GetGeoTransform() */ CPLErr CPL_STDCALL GDALGetGeoTransform( GDALDatasetH hDS, double * padfTransform ) { return( ((GDALDataset *) hDS)->GetGeoTransform(padfTransform) ); } /************************************************************************/ /* SetGeoTransform() */ /************************************************************************/ /** * Set the affine transformation coefficients. * * See GetGeoTransform() for details on the meaning of the padfTransform * coefficients. * * This method does the same thing as the C GDALSetGeoTransform() function. * * @param padfTransform a six double buffer containing the transformation * coefficients to be written with the dataset. * * @return CE_None on success, or CE_Failure if this transform cannot be * written. */ CPLErr GDALDataset::SetGeoTransform( double * ) { if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) ) CPLError( CE_Failure, CPLE_NotSupported, "SetGeoTransform() not supported for this dataset." ); return( CE_Failure ); } /************************************************************************/ /* GDALSetGeoTransform() */ /************************************************************************/ /** * @see GDALDataset::SetGeoTransform() */ CPLErr CPL_STDCALL GDALSetGeoTransform( GDALDatasetH hDS, double * padfTransform ) { return( ((GDALDataset *) hDS)->SetGeoTransform(padfTransform) ); } /************************************************************************/ /* GetInternalHandle() */ /************************************************************************/ /** * Fetch a format specific internally meaningful handle. * * This method is the same as the C GDALGetInternalHandle() method. * * @param pszHandleName the handle name desired. The meaningful names * will be specific to the file format. * * @return the desired handle value, or NULL if not recognised/supported. */ void *GDALDataset::GetInternalHandle( const char * ) { return( NULL ); } /************************************************************************/ /* GDALGetInternalHandle() */ /************************************************************************/ /** * @see GDALDataset::GetInternalHandle() */ void * CPL_STDCALL GDALGetInternalHandle( GDALDatasetH hDS, const char * pszRequest ) { return( ((GDALDataset *) hDS)->GetInternalHandle(pszRequest) ); } /************************************************************************/ /* GetDriver() */ /************************************************************************/ /** * Fetch the driver to which this dataset relates. * * This method is the same as the C GDALGetDatasetDriver() function. * * @return the driver on which the dataset was created with GDALOpen() or * GDALCreate(). */ GDALDriver * GDALDataset::GetDriver() { return poDriver; } /************************************************************************/ /* GDALGetDatasetDriver() */ /************************************************************************/ /** * @see GDALDataset::GetDriver() */ GDALDriverH CPL_STDCALL GDALGetDatasetDriver( GDALDatasetH hDataset ) { return (GDALDriverH) ((GDALDataset *) hDataset)->GetDriver(); } /************************************************************************/ /* Reference() */ /************************************************************************/ /** * Add one to dataset reference count. * * The reference is one after instantiation. * * This method is the same as the C GDALReferenceDataset() function. * * @return the post-increment reference count. */ int GDALDataset::Reference() { return ++nRefCount; } /************************************************************************/ /* GDALReferenceDataset() */ /************************************************************************/ /** * @see GDALDataset::Reference() */ int CPL_STDCALL GDALReferenceDataset( GDALDatasetH hDataset ) { return ((GDALDataset *) hDataset)->Reference(); } /************************************************************************/ /* Dereference() */ /************************************************************************/ /** * Subtract one from dataset reference count. * * The reference is one after instantiation. Generally when the reference * count has dropped to zero the dataset may be safely deleted (closed). * * This method is the same as the C GDALDereferenceDataset() function. * * @return the post-decrement reference count. */ int GDALDataset::Dereference() { return --nRefCount; } /************************************************************************/ /* GDALDereferenceDataset() */ /************************************************************************/ /** * @see GDALDataset::Dereference() */ int CPL_STDCALL GDALDereferenceDataset( GDALDatasetH hDataset ) { return ((GDALDataset *) hDataset)->Dereference(); } /************************************************************************/ /* GetShared() */ /************************************************************************/ /** * Returns shared flag. * * @return TRUE if the GDALDataset is available for sharing, or FALSE if not. */ int GDALDataset::GetShared() { return bShared; } /************************************************************************/ /* MarkAsShared() */ /************************************************************************/ /** * Mark this dataset as available for sharing. */ void GDALDataset::MarkAsShared() { CPLAssert( !bShared ); bShared = TRUE; } /************************************************************************/ /* GetGCPCount() */ /************************************************************************/ /** * Get number of GCPs. * * This method is the same as the C function GDALGetGCPCount(). * * @return number of GCPs for this dataset. Zero if there are none. */ int GDALDataset::GetGCPCount() { return 0; } /************************************************************************/ /* GDALGetGCPCount() */ /************************************************************************/ /** * @see GDALDataset::GetGCPCount() */ int CPL_STDCALL GDALGetGCPCount( GDALDatasetH hDS ) { return ((GDALDataset *) hDS)->GetGCPCount(); } /************************************************************************/ /* GetGCPProjection() */ /************************************************************************/ /** * Get output projection for GCPs. * * This method is the same as the C function GDALGetGCPProjection(). * * The projection string follows the normal rules from GetProjectionRef(). * * @return internal projection string or "" if there are no GCPs. */ const char *GDALDataset::GetGCPProjection() { return ""; } /************************************************************************/ /* GDALGetGCPProjection() */ /************************************************************************/ /** * @see GDALDataset::GetGCPProjection() */ const char * CPL_STDCALL GDALGetGCPProjection( GDALDatasetH hDS ) { return ((GDALDataset *) hDS)->GetGCPProjection(); } /************************************************************************/ /* GetGCPs() */ /************************************************************************/ /** * Fetch GCPs. * * This method is the same as the C function GDALGetGCPs(). * * @return pointer to internal GCP structure list. It should not be modified, * and may change on the next GDAL call. */ const GDAL_GCP *GDALDataset::GetGCPs() { return NULL; } /************************************************************************/ /* GDALGetGCPs() */ /************************************************************************/ /** * @see GDALDataset::GetGCPs() */ const GDAL_GCP * CPL_STDCALL GDALGetGCPs( GDALDatasetH hDS ) { return ((GDALDataset *) hDS)->GetGCPs(); } /************************************************************************/ /* SetGCPs() */ /************************************************************************/ /** * Assign GCPs. * * This method is the same as the C function GDALSetGCPs(). * * This method assigns the passed set of GCPs to this dataset, as well as * setting their coordinate system. Internally copies are made of the * coordinate system and list of points, so the caller remains resposible for * deallocating these arguments if appropriate. * * Most formats do not support setting of GCPs, even foramts that can * handle GCPs. These formats will return CE_Failure. * * @param nGCPCount number of GCPs being assigned. * * @param pasGCPList array of GCP structures being assign (nGCPCount in array). * * @param pszGCPProjection the new OGC WKT coordinate system to assign for the * GCP output coordinates. This parameter should be "" if no output coordinate * system is known. * * @return CE_None on success, CE_Failure on failure (including if action is * not supported for this format). */ CPLErr GDALDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList, const char * pszGCPProjection ) { (void) nGCPCount; (void) pasGCPList; (void) pszGCPProjection; if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) ) CPLError( CE_Failure, CPLE_NotSupported, "Dataset does not support the SetGCPs() method." ); return CE_Failure; } /************************************************************************/ /* GDALSetGCPs() */ /************************************************************************/ /** * @see GDALDataset::SetGCPs() */ CPLErr CPL_STDCALL GDALSetGCPs( GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList, const char *pszGCPProjection ) { return ((GDALDataset *) hDS)->SetGCPs( nGCPCount, pasGCPList, pszGCPProjection ); } /************************************************************************/ /* BuildOverviews() */ /************************************************************************/ /** * Build raster overview(s) * * If the operation is unsupported for the indicated dataset, then * CE_Failure is returned, and CPLGetLastErrorNo() will return * CPLE_NotSupported. * * This method is the same as the C function GDALBuildOverviews(). * * @param pszResampling one of "NEAREST", "AVERAGE" or "MODE" controlling * the downsampling method applied. * @param nOverviews number of overviews to build. * @param panOverviewList the list of overview decimation factors to build. * @param nBand number of bands to build overviews for in panBandList. Build * for all bands if this is 0. * @param panBandList list of band numbers. * @param pfnProgress a function to call to report progress, or NULL. * @param pProgressData application data to pass to the progress function. * * @return CE_None on success or CE_Failure if the operation doesn't work. * * For example, to build overview level 2, 4 and 8 on all bands the following * call could be made: *
* int anOverviewList[3] = { 2, 4, 8 };
*
* poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, NULL,
* GDALDummyProgress, NULL );
*
*/
CPLErr GDALDataset::BuildOverviews( const char *pszResampling,
int nOverviews, int *panOverviewList,
int nListBands, int *panBandList,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
CPLErr eErr;
int *panAllBandList = NULL;
if( nListBands == 0 )
{
nListBands = GetRasterCount();
panAllBandList = (int *) CPLMalloc(sizeof(int) * nListBands);
for( int i = 0; i < nListBands; i++ )
panAllBandList[i] = i+1;
panBandList = panAllBandList;
}
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
eErr = IBuildOverviews( pszResampling, nOverviews, panOverviewList,
nListBands, panBandList, pfnProgress, pProgressData );
if( panAllBandList != NULL )
CPLFree( panAllBandList );
return eErr;
}
/************************************************************************/
/* GDALBuildOverviews() */
/************************************************************************/
/**
* @see GDALDataset::BuildOverviews()
*/
CPLErr CPL_STDCALL GDALBuildOverviews( GDALDatasetH hDataset,
const char *pszResampling,
int nOverviews, int *panOverviewList,
int nListBands, int *panBandList,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
return ((GDALDataset *) hDataset)->BuildOverviews(
pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
pfnProgress, pProgressData );
}
/************************************************************************/
/* IBuildOverviews() */
/* */
/* Default implementation. */
/************************************************************************/
CPLErr GDALDataset::IBuildOverviews( const char *pszResampling,
int nOverviews, int *panOverviewList,
int nListBands, int *panBandList,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
if( oOvManager.IsInitialized() )
return oOvManager.BuildOverviews( NULL, pszResampling,
nOverviews, panOverviewList,
nListBands, panBandList,
pfnProgress, pProgressData );
else
{
CPLError( CE_Failure, CPLE_NotSupported,
"BuildOverviews() not supported for this dataset." );
return( CE_Failure );
}
}
/************************************************************************/
/* IRasterIO() */
/* */
/* The default implementation of IRasterIO() is to pass the */
/* request off to each band objects rasterio methods with */
/* appropriate arguments. */
/************************************************************************/
CPLErr GDALDataset::IRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount, int *panBandMap,
int nPixelSpace, int nLineSpace, int nBandSpace)
{
int iBandIndex;
CPLErr eErr = CE_None;
for( iBandIndex = 0;
iBandIndex < nBandCount && eErr == CE_None;
iBandIndex++ )
{
GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
GByte *pabyBandData;
pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace;
eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
(void *) pabyBandData, nBufXSize, nBufYSize,
eBufType, nPixelSpace, nLineSpace );
}
return eErr;
}
/************************************************************************/
/* RasterIO() */
/************************************************************************/
/**
* Read/write a region of image data from multiple bands.
*
* This method allows reading a region of one or more GDALRasterBands from
* this dataset into a buffer, or writing data from a buffer into a region
* of the GDALRasterBands. It automatically takes care of data type
* translation if the data type (eBufType) of the buffer is different than
* that of the GDALRasterBand.
* The method also takes care of image decimation / replication if the
* buffer size (nBufXSize x nBufYSize) is different than the size of the
* region being accessed (nXSize x nYSize).
*
* The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
* writing from various organization of buffers.
*
* For highest performance full resolution data access, read and write
* on "block boundaries" as returned by GetBlockSize(), or use the
* ReadBlock() and WriteBlock() methods.
*
* This method is the same as the C GDALDatasetRasterIO() function.
*
* @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
* write a region of data.
*
* @param nXOff The pixel offset to the top left corner of the region
* of the band to be accessed. This would be zero to start from the left side.
*
* @param nYOff The line offset to the top left corner of the region
* of the band to be accessed. This would be zero to start from the top.
*
* @param nXSize The width of the region of the band to be accessed in pixels.
*
* @param nYSize The height of the region of the band to be accessed in lines.
*
* @param pData The buffer into which the data should be read, or from which
* it should be written. This buffer must contain at least
* nBufXSize * nBufYSize * nBandCount words of type eBufType. It is organized
* in left to right,top to bottom pixel order. Spacing is controlled by the
* nPixelSpace, and nLineSpace parameters.
*
* @param nBufXSize the width of the buffer image into which the desired region
* is to be read, or from which it is to be written.
*
* @param nBufYSize the height of the buffer image into which the desired
* region is to be read, or from which it is to be written.
*
* @param eBufType the type of the pixel values in the pData data buffer. The
* pixel values will automatically be translated to/from the GDALRasterBand
* data type as needed.
*
* @param nBandCount the number of bands being read or written.
*
* @param panBandMap the list of nBandCount band numbers being read/written.
* Note band numbers are 1 based. This may be NULL to select the first
* nBandCount bands.
*
* @param nPixelSpace The byte offset from the start of one pixel value in
* pData to the start of the next pixel value within a scanline. If defaulted
* (0) the size of the datatype eBufType is used.
*
* @param nLineSpace The byte offset from the start of one scanline in
* pData to the start of the next. If defaulted the size of the datatype
* eBufType * nBufXSize is used.
*
* @param nBandSpace the byte offset from the start of one bands data to the
* start of the next. If defaulted (zero) the value will be
* nLineSpace * nBufYSize implying band sequential organization
* of the data buffer.
*
* @return CE_Failure if the access fails, otherwise CE_None.
*/
CPLErr GDALDataset::RasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount, int *panBandMap,
int nPixelSpace, int nLineSpace, int nBandSpace )
{
int i;
int bNeedToFreeBandMap = FALSE;
CPLErr eErr = CE_None;
/* -------------------------------------------------------------------- */
/* Some size values are "noop". Lets just return to avoid */
/* stressing lower level functions. */
/* -------------------------------------------------------------------- */
if( nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1 )
{
CPLDebug( "GDAL",
"RasterIO() skipped for odd window or buffer size.\n"
" Window = (%d,%d)x%dx%d\n"
" Buffer = %dx%d\n",
nXOff, nYOff, nXSize, nYSize,
nBufXSize, nBufYSize );
}
/* -------------------------------------------------------------------- */
/* If pixel and line spaceing are defaulted assign reasonable */
/* value assuming a packed buffer. */
/* -------------------------------------------------------------------- */
if( nPixelSpace == 0 )
nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
if( nLineSpace == 0 )
nLineSpace = nPixelSpace * nBufXSize;
if( nBandSpace == 0 )
nBandSpace = nLineSpace * nBufYSize;
if( panBandMap == NULL )
{
panBandMap = (int *) CPLMalloc(sizeof(int) * nBandCount);
for( i = 0; i < nBandCount; i++ )
panBandMap[i] = i+1;
bNeedToFreeBandMap = TRUE;
}
/* -------------------------------------------------------------------- */
/* Do some validation of parameters. */
/* -------------------------------------------------------------------- */
if( nXOff < 0 || nXOff + nXSize > nRasterXSize
|| nYOff < 0 || nYOff + nYSize > nRasterYSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Access window out of range in RasterIO(). Requested\n"
"(%d,%d) of size %dx%d on raster of %dx%d.",
nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize );
eErr = CE_Failure;
}
if( eRWFlag != GF_Read && eRWFlag != GF_Write )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
eRWFlag );
eErr = CE_Failure;
}
for( i = 0; i < nBandCount && eErr == CE_None; i++ )
{
if( panBandMap[i] < 1 || panBandMap[i] > GetRasterCount() )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"panBandMap[%d] = %d, this band does not exist on dataset.",
i, panBandMap[i] );
eErr = CE_Failure;
}
if( eErr == CE_None && GetRasterBand( panBandMap[i] ) == NULL )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"panBandMap[%d]=%d, this band should exist but is NULL!",
i, panBandMap[i] );
eErr = CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* We are being forced to use cached IO instead of a driver */
/* specific implementation. */
/* -------------------------------------------------------------------- */
if( bForceCachedIO )
{
eErr =
BlockBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize, eBufType,
nBandCount, panBandMap,
nPixelSpace, nLineSpace, nBandSpace );
}
/* -------------------------------------------------------------------- */
/* Call the format specific function. */
/* -------------------------------------------------------------------- */
else if( eErr == CE_None )
{
eErr =
IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize, eBufType,
nBandCount, panBandMap,
nPixelSpace, nLineSpace, nBandSpace );
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
if( bNeedToFreeBandMap )
CPLFree( panBandMap );
return eErr;
}
/************************************************************************/
/* GDALDatasetRasterIO() */
/************************************************************************/
/**
* @see GDALDataset::RasterIO()
*/
CPLErr CPL_STDCALL
GDALDatasetRasterIO( GDALDatasetH hDS, GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount, int *panBandMap,
int nPixelSpace, int nLineSpace, int nBandSpace )
{
GDALDataset *poDS = (GDALDataset *) hDS;
return( poDS->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize, eBufType,
nBandCount, panBandMap,
nPixelSpace, nLineSpace, nBandSpace ) );
}
/************************************************************************/
/* GetOpenDatasets() */
/************************************************************************/
/**
* Fetch all open GDAL dataset handles.
*
* This method is the same as the C function GDALGetOpenDatasets().
*
* NOTE: This method is not thread safe. The returned list may changed
* at any time.
*
* @param pnCount integer into which to place the count of dataset pointers
* being returned.
*
* @return a pointer to an array of dataset handles.
*/
GDALDataset **GDALDataset::GetOpenDatasets( int *pnCount )
{
*pnCount = nGDALDatasetCount;
return (GDALDataset **) papoGDALDatasetList;
}
/************************************************************************/
/* GDALGetOpenDatasets() */
/************************************************************************/
/**
* @see GDALDataset::GetOpenDatasets()
*/
void CPL_STDCALL GDALGetOpenDatasets( GDALDatasetH **ppahDSList, int *pnCount )
{
*ppahDSList = (GDALDatasetH *) GDALDataset::GetOpenDatasets( pnCount);
}
/************************************************************************/
/* GDALGetAccess() */
/************************************************************************/
/**
* @see GDALDataset::GetAccess()
*/
int CPL_STDCALL GDALGetAccess( GDALDatasetH hDS )
{
return ((GDALDataset *) hDS)->GetAccess();
}
/************************************************************************/
/* AdviseRead() */
/************************************************************************/
/**
* Advise driver of upcoming read requests.
*
* Some GDAL drivers operate more efficiently if they know in advance what
* set of upcoming read requests will be made. The AdviseRead() method allows
* an application to notify the driver of the region and bands of interest,
* and at what resolution the region will be read.
*
* Many drivers just ignore the AdviseRead() call, but it can dramatically
* accelerate access via some drivers.
*
* @param nXOff The pixel offset to the top left corner of the region
* of the band to be accessed. This would be zero to start from the left side.
*
* @param nYOff The line offset to the top left corner of the region
* of the band to be accessed. This would be zero to start from the top.
*
* @param nXSize The width of the region of the band to be accessed in pixels.
*
* @param nYSize The height of the region of the band to be accessed in lines.
*
* @param nBufXSize the width of the buffer image into which the desired region
* is to be read, or from which it is to be written.
*
* @param nBufYSize the height of the buffer image into which the desired
* region is to be read, or from which it is to be written.
*
* @param eBufType the type of the pixel values in the pData data buffer. The
* pixel values will automatically be translated to/from the GDALRasterBand
* data type as needed.
*
* @param nBandCount the number of bands being read or written.
*
* @param panBandMap the list of nBandCount band numbers being read/written.
* Note band numbers are 1 based. This may be NULL to select the first
* nBandCount bands.
*
* @param papszOptions a list of name=value strings with special control
* options. Normally this is NULL.
*
* @return CE_Failure if the request is invalid and CE_None if it works or
* is ignored.
*/
CPLErr GDALDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
int nBufXSize, int nBufYSize,
GDALDataType eDT,
int nBandCount, int *panBandMap,
char **papszOptions )
{
int iBand;
for( iBand = 0; iBand < nBandCount; iBand++ )
{
CPLErr eErr;
GDALRasterBand *poBand;
if( panBandMap == NULL )
poBand = GetRasterBand(iBand+1);
else
poBand = GetRasterBand(panBandMap[iBand]);
eErr = poBand->AdviseRead( nXOff, nYOff, nXSize, nYSize,
nBufXSize, nBufYSize, eDT, papszOptions );
if( eErr != CE_None )
return eErr;
}
return CE_None;
}
/************************************************************************/
/* GDALDatasetAdviseRead() */
/************************************************************************/
CPLErr CPL_STDCALL
GDALDatasetAdviseRead( GDALDatasetH hDS,
int nXOff, int nYOff, int nXSize, int nYSize,
int nBufXSize, int nBufYSize, GDALDataType eDT,
int nBandCount, int *panBandMap,char **papszOptions )
{
return ((GDALDataset *) hDS)->AdviseRead( nXOff, nYOff, nXSize, nYSize,
nBufXSize, nBufYSize, eDT,
nBandCount, panBandMap,
papszOptions );
}
/************************************************************************/
/* GDALOpen() */
/************************************************************************/
/**
* Open a raster file as a GDALDataset.
*
* This function will try to open the passed file, or virtual dataset
* name by invoking the Open method of each registered GDALDriver in turn.
* The first successful open will result in a returned dataset. If all
* drivers fail then NULL is returned.
*
* \sa GDALOpenShared()
*
* @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 eAccess the desired access, either GA_Update or GA_ReadOnly. Many
* drivers support only read only access.
*
* @return A GDALDatasetH handle or NULL on failure. For C++ applications
* this handle can be cast to a GDALDataset *.
*/
GDALDatasetH CPL_STDCALL
GDALOpen( const char * pszFilename, GDALAccess eAccess )
{
int iDriver;
GDALDriverManager *poDM = GetGDALDriverManager();
GDALOpenInfo oOpenInfo( pszFilename, eAccess );
CPLLocaleC oLocaleForcer;
CPLErrorReset();
for( iDriver = 0; iDriver < poDM->GetDriverCount(); iDriver++ )
{
GDALDriver *poDriver = poDM->GetDriver( iDriver );
GDALDataset *poDS;
poDS = poDriver->pfnOpen( &oOpenInfo );
if( poDS != NULL )
{
poDS->SetDescription( pszFilename );
if( poDS->poDriver == NULL )
poDS->poDriver = poDriver;
CPLDebug( "GDAL", "GDALOpen(%s) succeeds as %s.",
pszFilename, poDriver->GetDescription() );
return (GDALDatasetH) poDS;
}
if( CPLGetLastErrorNo() != 0 )
return NULL;
}
if( oOpenInfo.bStatOK )
CPLError( CE_Failure, CPLE_OpenFailed,
"`%s' not recognised as a supported file format.\n",
pszFilename );
else
CPLError( CE_Failure, CPLE_OpenFailed,
"`%s' does not exist in the file system,\n"
"and is not recognised as a supported dataset name.\n",
pszFilename );
return NULL;
}
/************************************************************************/
/* GDALOpenShared() */
/************************************************************************/
/**
* Open a raster file as a GDALDataset.
*
* This function works the same as GDALOpen(), but allows the sharing of
* GDALDataset handles for a dataset with other callers to GDALOpenShared().
*
* In particular, GDALOpenShared() will first consult it's list of currently
* open and shared GDALDataset's, and if the GetDescription() name for one
* exactly matches the pszFilename passed to GDALOpenShared() it will be
* referenced and returned.
*
* \sa GDALOpen()
*
* @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 eAccess the desired access, either GA_Update or GA_ReadOnly. Many
* drivers support only read only access.
*
* @return A GDALDatasetH handle or NULL on failure. For C++ applications
* this handle can be cast to a GDALDataset *.
*/
GDALDatasetH CPL_STDCALL
GDALOpenShared( const char *pszFilename, GDALAccess eAccess )
{
/* -------------------------------------------------------------------- */
/* First scan the existing list to see if it could already */
/* contain the requested dataset. */
/* -------------------------------------------------------------------- */
{
CPLMutexHolderD( &hDLMutex );
int i;
for( i = 0; i < nGDALDatasetCount; i++ )
{
if( strcmp(pszFilename,
papoGDALDatasetList[i]->GetDescription()) == 0
&& (eAccess == GA_ReadOnly
|| papoGDALDatasetList[i]->GetAccess() == eAccess ) )
{
papoGDALDatasetList[i]->Reference();
return papoGDALDatasetList[i];
}
}
}
/* -------------------------------------------------------------------- */
/* Try opening the the requested dataset. */
/* -------------------------------------------------------------------- */
GDALDataset *poDataset;
poDataset = (GDALDataset *) GDALOpen( pszFilename, eAccess );
if( poDataset != NULL )
poDataset->MarkAsShared();
return (GDALDatasetH) poDataset;
}
/************************************************************************/
/* GDALClose() */
/************************************************************************/
/**
* Close GDAL dataset.
*
* For non-shared datasets (opened with GDALOpen()) the dataset is closed
* using the C++ "delete" operator, recovering all dataset related resources.
* For shared datasets (opened with GDALOpenShared()) the dataset is
* dereferenced, and closed only if the referenced count has dropped below 1.
*
* @param hDS The dataset to close. May be cast from a "GDALDataset *".
*/
void CPL_STDCALL GDALClose( GDALDatasetH hDS )
{
GDALDataset *poDS = (GDALDataset *) hDS;
int i;
CPLMutexHolderD( &hDLMutex );
CPLLocaleC oLocaleForcer;
/* -------------------------------------------------------------------- */
/* If this file is in the shared dataset list then dereference */
/* it, and only delete/remote it if the reference count has */
/* dropped to zero. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nGDALDatasetCount; i++ )
{
if( papoGDALDatasetList[i] == poDS )
{
if( poDS->Dereference() > 0 )
return;
delete poDS;
return;
}
}
/* -------------------------------------------------------------------- */
/* This is not shared dataset, so directly delete it. */
/* -------------------------------------------------------------------- */
delete poDS;
}
/************************************************************************/
/* GDALDumpOpenDataset() */
/************************************************************************/
/**
* List open datasets.
*
* Dumps a list of all open datasets (shared or not) to the indicated
* text file (may be stdout or stderr). This function is primariliy intended
* to assist in debugging "dataset leaks" and reference counting issues.
* The information reported includes the dataset name, referenced count,
* shared status, driver name, size, and band count.
*/
int CPL_STDCALL GDALDumpOpenDatasets( FILE *fp )
{
CPLMutexHolderD( &hDLMutex );
int i;
if( nGDALDatasetCount > 0 )
VSIFPrintf( fp, "Open GDAL Datasets:\n" );
for( i = 0; i < nGDALDatasetCount; i++ )
{
const char *pszDriverName;
GDALDataset *poDS = (GDALDataset *) papoGDALDatasetList[i];
if( poDS->GetDriver() == NULL )
pszDriverName = "DriverIsNULL";
else
pszDriverName = poDS->GetDriver()->GetDescription();
poDS->Reference();
VSIFPrintf( fp, " %d %c %-6s %dx%dx%d %s\n",
poDS->Dereference(),
poDS->GetShared() ? 'S' : 'N',
pszDriverName,
poDS->GetRasterXSize(),
poDS->GetRasterYSize(),
poDS->GetRasterCount(),
poDS->GetDescription() );
}
return nGDALDatasetCount;
}