EVOLUTION-MANAGER
Edit File: gdaldataset.cpp
/****************************************************************************** * $Id: gdaldataset.cpp 27723 2014-09-22 18:21:08Z goatbar $ * * Project: GDAL Core * Purpose: Base class for raster file formats. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1998, 2003, Frank Warmerdam * Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org> * * 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_hash_set.h" #include "cpl_multiproc.h" #include <map> CPL_CVSID("$Id: gdaldataset.cpp 27723 2014-09-22 18:21:08Z goatbar $"); CPL_C_START GDALAsyncReader * GDALGetDefaultAsyncReader( GDALDataset *poDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount, int* panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace, char **papszOptions); CPL_C_END typedef struct { /* PID of the thread that mark the dataset as shared */ /* This may not be the actual PID, but the responsiblePID */ GIntBig nPID; char *pszDescription; GDALAccess eAccess; GDALDataset *poDS; } SharedDatasetCtxt; typedef struct { GDALDataset *poDS; /* In the case of a shared dataset, memorize the PID of the thread */ /* that marked the dataset as shared, so that we can remove it from */ /* the phSharedDatasetSet in the destructor of the dataset, even */ /* if GDALClose is called from a different thread */ /* Ideally, this should be stored in the GDALDataset object itself */ /* but this is inconvenient to change the object size at that time */ GIntBig nPIDCreatorForShared; } DatasetCtxt; /* Set of datasets opened as shared datasets (with GDALOpenShared) */ /* The values in the set are of type SharedDatasetCtxt */ static CPLHashSet* phSharedDatasetSet = NULL; /* Set of all datasets created in the constructor of GDALDataset */ /* The values in the set are of type DatasetCtxt */ static CPLHashSet* phAllDatasetSet = NULL; static void *hDLMutex = NULL; /* Static array of all datasets. Used by GDALGetOpenDatasets */ /* Not thread-safe. See GDALGetOpenDatasets */ static GDALDataset** ppDatasets = NULL; static unsigned long GDALSharedDatasetHashFunc(const void* elt) { SharedDatasetCtxt* psStruct = (SharedDatasetCtxt*) elt; return (unsigned long) (CPLHashSetHashStr(psStruct->pszDescription) ^ psStruct->eAccess ^ psStruct->nPID); } static int GDALSharedDatasetEqualFunc(const void* elt1, const void* elt2) { SharedDatasetCtxt* psStruct1 = (SharedDatasetCtxt*) elt1; SharedDatasetCtxt* psStruct2 = (SharedDatasetCtxt*) elt2; return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 && psStruct1->nPID == psStruct2->nPID && psStruct1->eAccess == psStruct2->eAccess; } static void GDALSharedDatasetFreeFunc(void* elt) { SharedDatasetCtxt* psStruct = (SharedDatasetCtxt*) elt; CPLFree(psStruct->pszDescription); CPLFree(psStruct); } static unsigned long GDALDatasetHashFunc(const void* elt) { DatasetCtxt* psStruct = (DatasetCtxt*) elt; return (unsigned long)(GUIntBig) psStruct->poDS; } static int GDALDatasetEqualFunc(const void* elt1, const void* elt2) { DatasetCtxt* psStruct1 = (DatasetCtxt*) elt1; DatasetCtxt* psStruct2 = (DatasetCtxt*) elt2; return psStruct1->poDS == psStruct2->poDS ; } static void GDALDatasetFreeFunc(void* elt) { DatasetCtxt* psStruct = (DatasetCtxt*) elt; CPLFree(psStruct); } /************************************************************************/ /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */ /************************************************************************/ /* The open-shared mutex must be used by the ProxyPool too */ void** GDALGetphDLMutex() { return &hDLMutex; } /* The current thread will act in the behalf of the thread of PID responsiblePID */ void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID) { GIntBig* pResponsiblePID = (GIntBig*) CPLGetTLS(CTLS_RESPONSIBLEPID); if (pResponsiblePID == NULL) { pResponsiblePID = (GIntBig*) CPLMalloc(sizeof(GIntBig)); CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE); } *pResponsiblePID = responsiblePID; } /* Get the PID of the thread that the current thread will act in the behalf of */ /* By default : the current thread acts in the behalf of itself */ GIntBig GDALGetResponsiblePIDForCurrentThread() { GIntBig* pResponsiblePID = (GIntBig*) CPLGetTLS(CTLS_RESPONSIBLEPID); if (pResponsiblePID == NULL) return CPLGetPID(); return *pResponsiblePID; } /************************************************************************/ /* ==================================================================== */ /* GDALDataset */ /* ==================================================================== */ /************************************************************************/ /** * \class GDALDataset "gdal_priv.h" * * A dataset encapsulating one or more raster bands. Details are * further discussed in the <a href="gdal_datamodel.html#GDALDataset">GDAL * Data Model</a>. * * 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 ); if (phAllDatasetSet == NULL) phAllDatasetSet = CPLHashSetNew(GDALDatasetHashFunc, GDALDatasetEqualFunc, GDALDatasetFreeFunc); DatasetCtxt* ctxt = (DatasetCtxt*)CPLMalloc(sizeof(DatasetCtxt)); ctxt->poDS = this; ctxt->nPIDCreatorForShared = -1; CPLHashSetInsert(phAllDatasetSet, ctxt); } /* -------------------------------------------------------------------- */ /* Set forced caching flag. */ /* -------------------------------------------------------------------- */ bForceCachedIO = CSLTestBoolean( CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") ); } /************************************************************************/ /* ~GDALDataset() */ /************************************************************************/ /** * \brief Destroy an open GDALDataset. * * This is the accepted method of closing a GDAL dataset and deallocating * all resources associated with it. * * Equivalent of the C callable GDALClose(). Except that GDALClose() first * decrements the reference count, and then closes only if it has dropped to * zero. * * For Windows users, it is not recommended to use the delete operator on the * dataset object because of known issues when allocating and freeing memory across * module boundaries. Calling GDALClose() is then a better option. */ GDALDataset::~GDALDataset() { int i; // we don't want to report destruction of datasets that // were never really open. if( nBands != 0 || !EQUAL(GetDescription(),"") ) { if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() ) CPLDebug( "GDAL", "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)", GetDescription(), this, (int)CPLGetPID(), (int)GDALGetResponsiblePIDForCurrentThread() ); else CPLDebug( "GDAL", "GDALClose(%s, this=%p)", GetDescription(), this ); } /* -------------------------------------------------------------------- */ /* Remove dataset from the "open" dataset list. */ /* -------------------------------------------------------------------- */ { CPLMutexHolderD( &hDLMutex ); if( phAllDatasetSet ) { DatasetCtxt sStruct; sStruct.poDS = this; DatasetCtxt* psStruct = (DatasetCtxt*) CPLHashSetLookup(phAllDatasetSet, &sStruct); GIntBig nPIDCreatorForShared = psStruct->nPIDCreatorForShared; CPLHashSetRemove(phAllDatasetSet, psStruct); if (bShared && phSharedDatasetSet != NULL) { SharedDatasetCtxt* psStruct; SharedDatasetCtxt sStruct; sStruct.nPID = nPIDCreatorForShared; sStruct.eAccess = eAccess; sStruct.pszDescription = (char*) GetDescription(); psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct); if (psStruct && psStruct->poDS == this) { CPLHashSetRemove(phSharedDatasetSet, psStruct); } else { CPLDebug("GDAL", "Should not happen. Cannot find %s, this=%p in phSharedDatasetSet", GetDescription(), this); } } if (CPLHashSetSize(phAllDatasetSet) == 0) { CPLHashSetDestroy(phAllDatasetSet); phAllDatasetSet = NULL; if (phSharedDatasetSet) { CPLHashSetDestroy(phSharedDatasetSet); } phSharedDatasetSet = NULL; CPLFree(ppDatasets); ppDatasets = NULL; } } } /* -------------------------------------------------------------------- */ /* 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() */ /************************************************************************/ /** * \brief 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. * * Using this method does not prevent use from calling GDALClose() * to properly close a dataset and ensure that important data not addressed * by FlushCache() is written in the file. * * 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() */ /************************************************************************/ /** * \brief Flush all write cached data to disk. * * @see GDALDataset::FlushCache(). */ void CPL_STDCALL GDALFlushCache( GDALDatasetH hDS ) { VALIDATE_POINTER0( hDS, "GDALFlushCache" ); ((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 ); 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() */ /************************************************************************/ /** * \brief 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()) 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; ReportError( CE_Failure, CPLE_NotSupported, "Dataset does not support the AddBand() method." ); return CE_Failure; } /************************************************************************/ /* GDALAddBand() */ /************************************************************************/ /** * \brief Add a band to a dataset. * * @see GDALDataset::AddBand(). */ CPLErr CPL_STDCALL GDALAddBand( GDALDatasetH hDataset, GDALDataType eType, char **papszOptions ) { VALIDATE_POINTER1( hDataset, "GDALAddBand", CE_Failure ); 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; GDALRasterBand** papoNewBands; if( papoBands == NULL ) papoNewBands = (GDALRasterBand **) VSICalloc(sizeof(GDALRasterBand*), MAX(nNewBand,nBands)); else papoNewBands = (GDALRasterBand **) VSIRealloc(papoBands, sizeof(GDALRasterBand*) * MAX(nNewBand,nBands)); if (papoNewBands == NULL) { ReportError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate band array"); return; } papoBands = papoNewBands; for( i = nBands; i < nNewBand; i++ ) papoBands[i] = NULL; nBands = MAX(nBands,nNewBand); } /* -------------------------------------------------------------------- */ /* Set the band. Resetting the band is currently not permitted. */ /* -------------------------------------------------------------------- */ if( papoBands[nNewBand-1] != NULL ) { ReportError(CE_Failure, CPLE_NotSupported, "Cannot set band %d as it is already set", nNewBand); return; } 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() */ /************************************************************************/ /** \brief Fetch raster width in pixels. Equivalent of the C function GDALGetRasterXSize(). @return the width in pixels of raster bands in this GDALDataset. */ int GDALDataset::GetRasterXSize() { return nRasterXSize; } /************************************************************************/ /* GDALGetRasterXSize() */ /************************************************************************/ /** * \brief Fetch raster width in pixels. * * @see GDALDataset::GetRasterXSize(). */ int CPL_STDCALL GDALGetRasterXSize( GDALDatasetH hDataset ) { VALIDATE_POINTER1( hDataset, "GDALGetRasterXSize", 0 ); return ((GDALDataset *) hDataset)->GetRasterXSize(); } /************************************************************************/ /* GetRasterYSize() */ /************************************************************************/ /** \brief Fetch raster height in pixels. Equivalent of the C function GDALGetRasterYSize(). @return the height in pixels of raster bands in this GDALDataset. */ int GDALDataset::GetRasterYSize() { return nRasterYSize; } /************************************************************************/ /* GDALGetRasterYSize() */ /************************************************************************/ /** * \brief Fetch raster height in pixels. * * @see GDALDataset::GetRasterYSize(). */ int CPL_STDCALL GDALGetRasterYSize( GDALDatasetH hDataset ) { VALIDATE_POINTER1( hDataset, "GDALGetRasterYSize", 0 ); return ((GDALDataset *) hDataset)->GetRasterYSize(); } /************************************************************************/ /* GetRasterBand() */ /************************************************************************/ /** \brief Fetch a band object for a dataset. Equivalent of the C function GDALGetRasterBand(). @param nBandId the index number of the band to fetch, from 1 to GetRasterCount(). @return the nBandId th band object */ GDALRasterBand * GDALDataset::GetRasterBand( int nBandId ) { if ( papoBands ) { if( nBandId < 1 || nBandId > nBands ) { ReportError( CE_Failure, CPLE_IllegalArg, "GDALDataset::GetRasterBand(%d) - Illegal band #\n", nBandId ); return NULL; } else return( papoBands[nBandId-1] ); } return NULL; } /************************************************************************/ /* GDALGetRasterBand() */ /************************************************************************/ /** * \brief Fetch a band object for a dataset. * @see GDALDataset::GetRasterBand(). */ GDALRasterBandH CPL_STDCALL GDALGetRasterBand( GDALDatasetH hDS, int nBandId ) { VALIDATE_POINTER1( hDS, "GDALGetRasterBand", NULL ); return( (GDALRasterBandH) ((GDALDataset *) hDS)->GetRasterBand(nBandId) ); } /************************************************************************/ /* GetRasterCount() */ /************************************************************************/ /** * \brief 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 papoBands ? nBands : 0; } /************************************************************************/ /* GDALGetRasterCount() */ /************************************************************************/ /** * \brief Fetch the number of raster bands on this dataset. * * @see GDALDataset::GetRasterCount(). */ int CPL_STDCALL GDALGetRasterCount( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetRasterCount", 0 ); return( ((GDALDataset *) hDS)->GetRasterCount() ); } /************************************************************************/ /* GetProjectionRef() */ /************************************************************************/ /** * \brief 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() */ /************************************************************************/ /** * \brief Fetch the projection definition string for this dataset. * * @see GDALDataset::GetProjectionRef() */ const char * CPL_STDCALL GDALGetProjectionRef( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetProjectionRef", NULL ); return( ((GDALDataset *) hDS)->GetProjectionRef() ); } /************************************************************************/ /* SetProjection() */ /************************************************************************/ /** * \brief 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( CPL_UNUSED const char * pszProjection ) { if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) ) ReportError( CE_Failure, CPLE_NotSupported, "Dataset does not support the SetProjection() method." ); return CE_Failure; } /************************************************************************/ /* GDALSetProjection() */ /************************************************************************/ /** * \brief Set the projection reference string for this dataset. * * @see GDALDataset::SetProjection() */ CPLErr CPL_STDCALL GDALSetProjection( GDALDatasetH hDS, const char * pszProjection ) { VALIDATE_POINTER1( hDS, "GDALSetProjection", CE_Failure ); return( ((GDALDataset *) hDS)->SetProjection(pszProjection) ); } /************************************************************************/ /* GetGeoTransform() */ /************************************************************************/ /** * \brief 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. * * 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() */ /************************************************************************/ /** * \brief Fetch the affine transformation coefficients. * * @see GDALDataset::GetGeoTransform() */ CPLErr CPL_STDCALL GDALGetGeoTransform( GDALDatasetH hDS, double * padfTransform ) { VALIDATE_POINTER1( hDS, "GDALGetGeoTransform", CE_Failure ); return( ((GDALDataset *) hDS)->GetGeoTransform(padfTransform) ); } /************************************************************************/ /* SetGeoTransform() */ /************************************************************************/ /** * \brief 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( CPL_UNUSED double * padfTransform ) { if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) ) ReportError( CE_Failure, CPLE_NotSupported, "SetGeoTransform() not supported for this dataset." ); return( CE_Failure ); } /************************************************************************/ /* GDALSetGeoTransform() */ /************************************************************************/ /** * \brief Set the affine transformation coefficients. * * @see GDALDataset::SetGeoTransform() */ CPLErr CPL_STDCALL GDALSetGeoTransform( GDALDatasetH hDS, CPL_UNUSED double * padfTransform ) { VALIDATE_POINTER1( hDS, "GDALSetGeoTransform", CE_Failure ); return( ((GDALDataset *) hDS)->SetGeoTransform(padfTransform) ); } /************************************************************************/ /* GetInternalHandle() */ /************************************************************************/ /** * \brief 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( CPL_UNUSED const char * pszHandleName ) { return( NULL ); } /************************************************************************/ /* GDALGetInternalHandle() */ /************************************************************************/ /** * \brief Fetch a format specific internally meaningful handle. * * @see GDALDataset::GetInternalHandle() */ void * CPL_STDCALL GDALGetInternalHandle( GDALDatasetH hDS, const char * pszRequest ) { VALIDATE_POINTER1( hDS, "GDALGetInternalHandle", NULL ); return( ((GDALDataset *) hDS)->GetInternalHandle(pszRequest) ); } /************************************************************************/ /* GetDriver() */ /************************************************************************/ /** * \brief 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() */ /************************************************************************/ /** * \brief Fetch the driver to which this dataset relates. * * @see GDALDataset::GetDriver() */ GDALDriverH CPL_STDCALL GDALGetDatasetDriver( GDALDatasetH hDataset ) { VALIDATE_POINTER1( hDataset, "GDALGetDatasetDriver", NULL ); return (GDALDriverH) ((GDALDataset *) hDataset)->GetDriver(); } /************************************************************************/ /* Reference() */ /************************************************************************/ /** * \brief 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() */ /************************************************************************/ /** * \brief Add one to dataset reference count. * * @see GDALDataset::Reference() */ int CPL_STDCALL GDALReferenceDataset( GDALDatasetH hDataset ) { VALIDATE_POINTER1( hDataset, "GDALReferenceDataset", 0 ); return ((GDALDataset *) hDataset)->Reference(); } /************************************************************************/ /* Dereference() */ /************************************************************************/ /** * \brief 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() */ /************************************************************************/ /** * \brief Subtract one from dataset reference count. * * @see GDALDataset::Dereference() */ int CPL_STDCALL GDALDereferenceDataset( GDALDatasetH hDataset ) { VALIDATE_POINTER1( hDataset, "GDALDereferenceDataset", 0 ); return ((GDALDataset *) hDataset)->Dereference(); } /************************************************************************/ /* GetShared() */ /************************************************************************/ /** * \brief Returns shared flag. * * @return TRUE if the GDALDataset is available for sharing, or FALSE if not. */ int GDALDataset::GetShared() { return bShared; } /************************************************************************/ /* MarkAsShared() */ /************************************************************************/ /** * \brief Mark this dataset as available for sharing. */ void GDALDataset::MarkAsShared() { CPLAssert( !bShared ); bShared = TRUE; GIntBig nPID = GDALGetResponsiblePIDForCurrentThread(); SharedDatasetCtxt* psStruct; /* Insert the dataset in the set of shared opened datasets */ CPLMutexHolderD( &hDLMutex ); if (phSharedDatasetSet == NULL) phSharedDatasetSet = CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc, GDALSharedDatasetFreeFunc); psStruct = (SharedDatasetCtxt*)CPLMalloc(sizeof(SharedDatasetCtxt)); psStruct->poDS = this; psStruct->nPID = nPID; psStruct->eAccess = eAccess; psStruct->pszDescription = CPLStrdup(GetDescription()); if(CPLHashSetLookup(phSharedDatasetSet, psStruct) != NULL) { CPLFree(psStruct); ReportError(CE_Failure, CPLE_AppDefined, "An existing shared dataset already has this description. This should not happen."); } else { CPLHashSetInsert(phSharedDatasetSet, psStruct); DatasetCtxt sStruct; sStruct.poDS = this; DatasetCtxt* psStruct = (DatasetCtxt*) CPLHashSetLookup(phAllDatasetSet, &sStruct); psStruct->nPIDCreatorForShared = nPID; } } /************************************************************************/ /* GetGCPCount() */ /************************************************************************/ /** * \brief 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() */ /************************************************************************/ /** * \brief Get number of GCPs. * * @see GDALDataset::GetGCPCount() */ int CPL_STDCALL GDALGetGCPCount( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetGCPCount", 0 ); return ((GDALDataset *) hDS)->GetGCPCount(); } /************************************************************************/ /* GetGCPProjection() */ /************************************************************************/ /** * \brief 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. * It should not be altered, freed or expected to last for long. */ const char *GDALDataset::GetGCPProjection() { return ""; } /************************************************************************/ /* GDALGetGCPProjection() */ /************************************************************************/ /** * \brief Get output projection for GCPs. * * @see GDALDataset::GetGCPProjection() */ const char * CPL_STDCALL GDALGetGCPProjection( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetGCPProjection", NULL ); return ((GDALDataset *) hDS)->GetGCPProjection(); } /************************************************************************/ /* GetGCPs() */ /************************************************************************/ /** * \brief 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() */ /************************************************************************/ /** * \brief Fetch GCPs. * * @see GDALDataset::GetGCPs() */ const GDAL_GCP * CPL_STDCALL GDALGetGCPs( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetGCPs", NULL ); return ((GDALDataset *) hDS)->GetGCPs(); } /************************************************************************/ /* SetGCPs() */ /************************************************************************/ /** * \brief 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 responsible for * deallocating these arguments if appropriate. * * Most formats do not support setting of GCPs, even formats 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) ) ReportError( CE_Failure, CPLE_NotSupported, "Dataset does not support the SetGCPs() method." ); return CE_Failure; } /************************************************************************/ /* GDALSetGCPs() */ /************************************************************************/ /** * \brief Assign GCPs. * * @see GDALDataset::SetGCPs() */ CPLErr CPL_STDCALL GDALSetGCPs( GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList, const char *pszGCPProjection ) { VALIDATE_POINTER1( hDS, "GDALSetGCPs", CE_Failure ); return ((GDALDataset *) hDS)->SetGCPs( nGCPCount, pasGCPList, pszGCPProjection ); } /************************************************************************/ /* BuildOverviews() */ /************************************************************************/ /** * \brief 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", "GAUSS", "CUBIC", "AVERAGE", "MODE", * "AVERAGE_MAGPHASE" or "NONE" controlling the downsampling method applied. * @param nOverviews number of overviews to build. * @param panOverviewList the list of overview decimation factors to build. * @param nListBands 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: * <pre> * int anOverviewList[3] = { 2, 4, 8 }; * * poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, NULL, * GDALDummyProgress, NULL ); * </pre> * * @see GDALRegenerateOverviews() */ 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() */ /************************************************************************/ /** * \brief Build raster overview(s) * * @see GDALDataset::BuildOverviews() */ CPLErr CPL_STDCALL GDALBuildOverviews( GDALDatasetH hDataset, const char *pszResampling, int nOverviews, int *panOverviewList, int nListBands, int *panBandList, GDALProgressFunc pfnProgress, void * pProgressData ) { VALIDATE_POINTER1( hDataset, "GDALBuildOverviews", CE_Failure ); 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( oOvManager.IsInitialized() ) return oOvManager.BuildOverviews( NULL, pszResampling, nOverviews, panOverviewList, nListBands, panBandList, pfnProgress, pProgressData ); else { ReportError( 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; const char* pszInterleave = NULL; CPLAssert( NULL != pData ); if (nXSize == nBufXSize && nYSize == nBufYSize && nBandCount > 1 && (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) != NULL && EQUAL(pszInterleave, "PIXEL")) { return BlockBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace ); } for( iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None; iBandIndex++ ) { GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]); GByte *pabyBandData; if (poBand == NULL) { eErr = CE_Failure; break; } pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace; eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, (void *) pabyBandData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace ); } return eErr; } /************************************************************************/ /* ValidateRasterIOOrAdviseReadParameters() */ /************************************************************************/ CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters( const char* pszCallingFunc, int* pbStopProcessingOnCENone, int nXOff, int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize, int nBandCount, int *panBandMap) { /* -------------------------------------------------------------------- */ /* 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", "%s skipped for odd window or buffer size.\n" " Window = (%d,%d)x%dx%d\n" " Buffer = %dx%d\n", pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize ); *pbStopProcessingOnCENone = TRUE; return CE_None; } CPLErr eErr = CE_None; *pbStopProcessingOnCENone = FALSE; if( nXOff < 0 || nXOff > INT_MAX - nXSize || nXOff + nXSize > nRasterXSize || nYOff < 0 || nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize ) { ReportError( CE_Failure, CPLE_IllegalArg, "Access window out of range in %s. Requested\n" "(%d,%d) of size %dx%d on raster of %dx%d.", pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize ); eErr = CE_Failure; } if( panBandMap == NULL && nBandCount > GetRasterCount() ) { ReportError( CE_Failure, CPLE_IllegalArg, "%s: nBandCount cannot be greater than %d", pszCallingFunc, GetRasterCount() ); eErr = CE_Failure; } for( int i = 0; i < nBandCount && eErr == CE_None; i++ ) { int iBand = (panBandMap != NULL) ? panBandMap[i] : i + 1; if( iBand < 1 || iBand > GetRasterCount() ) { ReportError( CE_Failure, CPLE_IllegalArg, "%s: panBandMap[%d] = %d, this band does not exist on dataset.", pszCallingFunc, i, iBand ); eErr = CE_Failure; } if( eErr == CE_None && GetRasterBand( iBand ) == NULL ) { ReportError( CE_Failure, CPLE_IllegalArg, "%s: panBandMap[%d]=%d, this band should exist but is NULL!", pszCallingFunc, i, iBand ); eErr = CE_Failure; } } return eErr; } /************************************************************************/ /* RasterIO() */ /************************************************************************/ /** * \brief 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 (0) 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 (0) 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 = 0; int bNeedToFreeBandMap = FALSE; CPLErr eErr = CE_None; if( NULL == pData ) { ReportError( CE_Failure, CPLE_AppDefined, "The buffer into which the data should be read is null" ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Do some validation of parameters. */ /* -------------------------------------------------------------------- */ if( eRWFlag != GF_Read && eRWFlag != GF_Write ) { ReportError( CE_Failure, CPLE_IllegalArg, "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.", eRWFlag ); return CE_Failure; } int bStopProcessing = FALSE; eErr = ValidateRasterIOOrAdviseReadParameters( "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, nBandCount, panBandMap); if( eErr != CE_None || bStopProcessing ) return eErr; /* -------------------------------------------------------------------- */ /* If pixel and line spacing are defaulted assign reasonable */ /* value assuming a packed buffer. */ /* -------------------------------------------------------------------- */ if( nPixelSpace == 0 ) nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8; if( nLineSpace == 0 ) { if (nPixelSpace > INT_MAX / nBufXSize) { ReportError( CE_Failure, CPLE_AppDefined, "Int overflow : %d x %d", nPixelSpace, nBufXSize ); return CE_Failure; } nLineSpace = nPixelSpace * nBufXSize; } /* The nBandCount > 1 test is necessary to allow reading only */ /* one band, even if the nLineSpace would overflow, but as it */ /* is not used in that case, it can be left to 0 (#3481) */ if( nBandSpace == 0 && nBandCount > 1 ) { if (nLineSpace > INT_MAX / nBufYSize) { ReportError( CE_Failure, CPLE_AppDefined, "Int overflow : %d x %d", nLineSpace, nBufYSize ); return CE_Failure; } nBandSpace = nLineSpace * nBufYSize; } if( panBandMap == NULL ) { panBandMap = (int *) VSIMalloc2(sizeof(int), nBandCount); if (panBandMap == NULL) { ReportError( CE_Failure, CPLE_OutOfMemory, "Out of memory while allocating band map array" ); return CE_Failure; } for( i = 0; i < nBandCount; i++ ) panBandMap[i] = i+1; bNeedToFreeBandMap = TRUE; } /* -------------------------------------------------------------------- */ /* 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() */ /************************************************************************/ /** * \brief Read/write a region of image data from multiple bands. * * @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 ) { VALIDATE_POINTER1( hDS, "GDALDatasetRasterIO", CE_Failure ); GDALDataset *poDS = (GDALDataset *) hDS; return( poDS->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace ) ); } /************************************************************************/ /* GetOpenDatasets() */ /************************************************************************/ static int GDALGetOpenDatasetsForeach(void* elt, void* user_data) { int* pnIndex = (int*) user_data; DatasetCtxt* psStruct = (DatasetCtxt*) elt; ppDatasets[*pnIndex] = psStruct->poDS; (*pnIndex) ++; return TRUE; } /** * \brief 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 change * at any time and it should not be freed. * * @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 ) { CPLMutexHolderD( &hDLMutex ); if (phAllDatasetSet != NULL) { int nIndex = 0; *pnCount = CPLHashSetSize(phAllDatasetSet); ppDatasets = (GDALDataset**) CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset*)); CPLHashSetForeach(phAllDatasetSet, GDALGetOpenDatasetsForeach, &nIndex); return ppDatasets; } else { *pnCount = 0; return NULL; } } /************************************************************************/ /* GDALGetOpenDatasets() */ /************************************************************************/ /** * \brief Fetch all open GDAL dataset handles. * * @see GDALDataset::GetOpenDatasets() */ void CPL_STDCALL GDALGetOpenDatasets( GDALDatasetH **ppahDSList, int *pnCount ) { VALIDATE_POINTER0( ppahDSList, "GDALGetOpenDatasets" ); VALIDATE_POINTER0( pnCount, "GDALGetOpenDatasets" ); *ppahDSList = (GDALDatasetH *) GDALDataset::GetOpenDatasets( pnCount); } /************************************************************************/ /* GDALCleanOpenDatasetsList() */ /************************************************************************/ /* Usefull when called from the child of a fork(), to avoid closing */ /* the datasets of the parent at the child termination */ void GDALNullifyOpenDatasetsList() { phAllDatasetSet = NULL; phSharedDatasetSet = NULL; ppDatasets = NULL; hDLMutex = NULL; } /************************************************************************/ /* GDALGetAccess() */ /************************************************************************/ /** * \brief Return access flag * * @see GDALDataset::GetAccess() */ int CPL_STDCALL GDALGetAccess( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetAccess", 0 ); return ((GDALDataset *) hDS)->GetAccess(); } /************************************************************************/ /* AdviseRead() */ /************************************************************************/ /** * \brief 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 eBufType, int nBandCount, int *panBandMap, char **papszOptions ) { int iBand; /* -------------------------------------------------------------------- */ /* Do some validation of parameters. */ /* -------------------------------------------------------------------- */ int bStopProcessing = FALSE; CPLErr eErr = ValidateRasterIOOrAdviseReadParameters( "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, nBandCount, panBandMap); if( eErr != CE_None || bStopProcessing ) return eErr; 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, eBufType, papszOptions ); if( eErr != CE_None ) return eErr; } return CE_None; } /************************************************************************/ /* GDALDatasetAdviseRead() */ /************************************************************************/ /** * \brief Advise driver of upcoming read requests. * * @see GDALDataset::AdviseRead() */ 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 ) { VALIDATE_POINTER1( hDS, "GDALDatasetAdviseRead", CE_Failure ); return ((GDALDataset *) hDS)->AdviseRead( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount, panBandMap, papszOptions ); } /************************************************************************/ /* GetFileList() */ /************************************************************************/ /** * \brief Fetch files forming dataset. * * Returns a list of files believed to be part of this dataset. If it returns * an empty list of files it means there is believed to be no local file * system files associated with the dataset (for instance a virtual dataset). * The returned file list is owned by the caller and should be deallocated * with CSLDestroy(). * * The returned filenames will normally be relative or absolute paths * depending on the path used to originally open the dataset. The strings * will be UTF-8 encoded. * * This method is the same as the C GDALGetFileList() function. * * @return NULL or a NULL terminated array of file names. */ char **GDALDataset::GetFileList() { CPLString osMainFilename = GetDescription(); int bMainFileReal; VSIStatBufL sStat; /* -------------------------------------------------------------------- */ /* Is the main filename even a real filesystem object? */ /* -------------------------------------------------------------------- */ bMainFileReal = VSIStatExL( osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG ) == 0; /* -------------------------------------------------------------------- */ /* Form new list. */ /* -------------------------------------------------------------------- */ char **papszList = NULL; if( bMainFileReal ) papszList = CSLAddString( papszList, osMainFilename ); /* -------------------------------------------------------------------- */ /* Do we have a known overview file? */ /* -------------------------------------------------------------------- */ if( oOvManager.IsInitialized() && oOvManager.poODS != NULL ) { char **papszOvrList = oOvManager.poODS->GetFileList(); papszList = CSLInsertStrings( papszList, -1, papszOvrList ); CSLDestroy( papszOvrList ); } /* -------------------------------------------------------------------- */ /* Do we have a known overview file? */ /* -------------------------------------------------------------------- */ if( oOvManager.HaveMaskFile() ) { char **papszMskList = oOvManager.poMaskDS->GetFileList(); char **papszIter = papszMskList; while( papszIter && *papszIter ) { if( CSLFindString( papszList, *papszIter ) < 0 ) papszList = CSLAddString( papszList, *papszIter ); papszIter ++; } CSLDestroy( papszMskList ); } /* -------------------------------------------------------------------- */ /* Do we have a world file? */ /* -------------------------------------------------------------------- */ if( bMainFileReal ) { const char* pszExtension = CPLGetExtension( osMainFilename ); if( strlen(pszExtension) > 2 ) { // first + last + 'w' char szDerivedExtension[4]; szDerivedExtension[0] = pszExtension[0]; szDerivedExtension[1] = pszExtension[strlen(pszExtension)-1]; szDerivedExtension[2] = 'w'; szDerivedExtension[3] = '\0'; CPLString osWorldFilename = CPLResetExtension( osMainFilename, szDerivedExtension ); if (oOvManager.papszInitSiblingFiles) { int iSibling = CSLFindString(oOvManager.papszInitSiblingFiles, CPLGetFilename(osWorldFilename)); if (iSibling >= 0) { osWorldFilename.resize(strlen(osWorldFilename) - strlen(oOvManager.papszInitSiblingFiles[iSibling])); osWorldFilename += oOvManager.papszInitSiblingFiles[iSibling]; papszList = CSLAddString( papszList, osWorldFilename ); } } else if( VSIStatExL( osWorldFilename, &sStat, VSI_STAT_EXISTS_FLAG ) == 0 ) papszList = CSLAddString( papszList, osWorldFilename ); } } return papszList; } /************************************************************************/ /* GDALGetFileList() */ /************************************************************************/ /** * \brief Fetch files forming dataset. * * @see GDALDataset::GetFileList() */ char ** CPL_STDCALL GDALGetFileList( GDALDatasetH hDS ) { VALIDATE_POINTER1( hDS, "GDALGetFileList", NULL ); return ((GDALDataset *) hDS)->GetFileList(); } /************************************************************************/ /* CreateMaskBand() */ /************************************************************************/ /** * \brief Adds a mask band to the dataset * * The default implementation of the CreateMaskBand() method is implemented * based on similar rules to the .ovr handling implemented using the * GDALDefaultOverviews object. A TIFF file with the extension .msk will * be created with the same basename as the original file, and it will have * one band. * The mask images will be deflate compressed tiled images with the same * block size as the original image if possible. * * Note that if you got a mask band with a previous call to GetMaskBand(), * it might be invalidated by CreateMaskBand(). So you have to call GetMaskBand() * again. * * @since GDAL 1.5.0 * * @param nFlags ignored. GMF_PER_DATASET will be assumed. * @return CE_None on success or CE_Failure on an error. * * @see http://trac.osgeo.org/gdal/wiki/rfc15_nodatabitmask * */ CPLErr GDALDataset::CreateMaskBand( int nFlags ) { if( oOvManager.IsInitialized() ) { CPLErr eErr = oOvManager.CreateMaskBand( nFlags, -1 ); if (eErr != CE_None) return eErr; /* Invalidate existing raster band masks */ int i; for(i=0;i<nBands;i++) { GDALRasterBand* poBand = papoBands[i]; if (poBand->bOwnMask) delete poBand->poMask; poBand->bOwnMask = false; poBand->poMask = NULL; } return CE_None; } ReportError( CE_Failure, CPLE_NotSupported, "CreateMaskBand() not supported for this dataset." ); return( CE_Failure ); } /************************************************************************/ /* GDALCreateDatasetMaskBand() */ /************************************************************************/ /** * \brief Adds a mask band to the dataset * @see GDALDataset::CreateMaskBand() */ CPLErr CPL_STDCALL GDALCreateDatasetMaskBand( GDALDatasetH hDS, int nFlags ) { VALIDATE_POINTER1( hDS, "GDALCreateDatasetMaskBand", CE_Failure ); return ((GDALDataset *) hDS)->CreateMaskBand( nFlags ); } /************************************************************************/ /* GDALOpen() */ /************************************************************************/ /** * \brief 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 and an error is issued. * * Several recommendations : * <ul> * <li>If you open a dataset object with GA_Update access, it is not recommended * to open a new dataset on the same underlying file.</li> * <li>The returned dataset should only be accessed by one thread at a time. If you * want to use it from different threads, you must add all necessary code (mutexes, etc.) * to avoid concurrent use of the object. (Some drivers, such as GeoTIFF, maintain internal * state variables that are updated each time a new block is read, thus preventing concurrent * use.) </li> * </ul> * * For drivers supporting the VSI virtual file API, it is possible to open * a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive * (see VSIInstallTarFileHandler()) or on a HTTP / FTP server (see VSIInstallCurlFileHandler()) * * In some situations (dealing with unverified data), the datasets can be opened in another * process through the \ref gdal_api_proxy mechanism. * * \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. It should be in UTF-8 * encoding. * * @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 ) { return GDALOpenInternal(pszFilename, eAccess, NULL); } /* The drivers listed in papszAllowedDrivers can be in any order */ /* Only the order of registration will be taken into account */ GDALDatasetH GDALOpenInternal( const char * pszFilename, GDALAccess eAccess, const char* const * papszAllowedDrivers) { GDALOpenInfo oOpenInfo( pszFilename, eAccess ); return GDALOpenInternal(oOpenInfo, papszAllowedDrivers); } GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo, const char* const * papszAllowedDrivers) { VALIDATE_POINTER1( oOpenInfo.pszFilename, "GDALOpen", NULL ); { int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP ); if( pnRecCount == NULL ) { pnRecCount = (int*) CPLMalloc(sizeof(int)); *pnRecCount = 0; CPLSetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP, pnRecCount, TRUE ); } if( *pnRecCount == 100 ) { CPLError(CE_Failure, CPLE_AppDefined, "GDALOpen() called with too many recursion levels"); return NULL; } (*pnRecCount) ++; } int iDriver; GDALDriverManager *poDM = GetGDALDriverManager(); CPLLocaleC oLocaleForcer; CPLErrorReset(); CPLAssert( NULL != poDM ); for( iDriver = -1; iDriver < poDM->GetDriverCount(); iDriver++ ) { GDALDriver *poDriver; GDALDataset *poDS; if( iDriver < 0 ) poDriver = GDALGetAPIPROXYDriver(); else { poDriver = poDM->GetDriver( iDriver ); if (papszAllowedDrivers != NULL && CSLFindString((char**)papszAllowedDrivers, GDALGetDriverShortName(poDriver)) == -1) continue; } if ( poDriver->pfnOpen == NULL ) continue; poDS = poDriver->pfnOpen( &oOpenInfo ); if( poDS != NULL ) { if( strlen(poDS->GetDescription()) == 0 ) poDS->SetDescription( oOpenInfo.pszFilename ); if( poDS->poDriver == NULL ) poDS->poDriver = poDriver; if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() ) CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s (pid=%d, responsiblePID=%d).", oOpenInfo.pszFilename, poDS, poDriver->GetDescription(), (int)CPLGetPID(), (int)GDALGetResponsiblePIDForCurrentThread() ); else CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s.", oOpenInfo.pszFilename, poDS, poDriver->GetDescription() ); int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP ); if( pnRecCount ) (*pnRecCount) --; return (GDALDatasetH) poDS; } if( CPLGetLastErrorNo() != 0 ) { int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP ); if( pnRecCount ) (*pnRecCount) --; return NULL; } } if( oOpenInfo.bStatOK ) CPLError( CE_Failure, CPLE_OpenFailed, "`%s' not recognised as a supported file format.\n", oOpenInfo.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", oOpenInfo.pszFilename ); int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP ); if( pnRecCount ) (*pnRecCount) --; return NULL; } /************************************************************************/ /* GDALOpenShared() */ /************************************************************************/ /** * \brief 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. * * Starting with GDAL 1.6.0, if GDALOpenShared() is called on the same pszFilename * from two different threads, a different GDALDataset object will be returned as * it is not safe to use the same dataset from different threads, unless the user * does explicitely use mutexes in its code. * * For drivers supporting the VSI virtual file API, it is possible to open * a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive * (see VSIInstallTarFileHandler()) or on a HTTP / FTP server (see VSIInstallCurlFileHandler()) * * In some situations (dealing with unverified data), the datasets can be opened in another * process through the \ref gdal_api_proxy mechanism. * * \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. It should be in * UTF-8 encoding. * * @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 ) { VALIDATE_POINTER1( pszFilename, "GDALOpenShared", NULL ); /* -------------------------------------------------------------------- */ /* First scan the existing list to see if it could already */ /* contain the requested dataset. */ /* -------------------------------------------------------------------- */ { CPLMutexHolderD( &hDLMutex ); if (phSharedDatasetSet != NULL) { GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread(); SharedDatasetCtxt* psStruct; SharedDatasetCtxt sStruct; sStruct.nPID = nThisPID; sStruct.pszDescription = (char*) pszFilename; sStruct.eAccess = eAccess; psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct); if (psStruct == NULL && eAccess == GA_ReadOnly) { sStruct.eAccess = GA_Update; psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct); } if (psStruct) { psStruct->poDS->Reference(); return psStruct->poDS; } } } /* -------------------------------------------------------------------- */ /* Try opening the the requested dataset. */ /* -------------------------------------------------------------------- */ GDALDataset *poDataset; poDataset = (GDALDataset *) GDALOpen( pszFilename, eAccess ); if( poDataset != NULL ) { if (strcmp(pszFilename, poDataset->GetDescription()) != 0) { CPLError(CE_Warning, CPLE_NotSupported, "A dataset opened by GDALOpenShared should have the same filename (%s) " "and description (%s)", pszFilename, poDataset->GetDescription()); } else { poDataset->MarkAsShared(); } } return (GDALDatasetH) poDataset; } /************************************************************************/ /* GDALClose() */ /************************************************************************/ /** * \brief 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 ) { VALIDATE_POINTER0( hDS, "GDALClose" ); GDALDataset *poDS = (GDALDataset *) hDS; CPLMutexHolderD( &hDLMutex ); CPLLocaleC oLocaleForcer; if (poDS->GetShared()) { /* -------------------------------------------------------------------- */ /* 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. */ /* -------------------------------------------------------------------- */ if( poDS->Dereference() > 0 ) return; delete poDS; return; } /* -------------------------------------------------------------------- */ /* This is not shared dataset, so directly delete it. */ /* -------------------------------------------------------------------- */ delete poDS; } /************************************************************************/ /* GDALDumpOpenDataset() */ /************************************************************************/ static int GDALDumpOpenSharedDatasetsForeach(void* elt, void* user_data) { SharedDatasetCtxt* psStruct = (SharedDatasetCtxt*) elt; FILE *fp = (FILE*) user_data; const char *pszDriverName; GDALDataset *poDS = psStruct->poDS; if( poDS->GetDriver() == NULL ) pszDriverName = "DriverIsNULL"; else pszDriverName = poDS->GetDriver()->GetDescription(); poDS->Reference(); VSIFPrintf( fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(), poDS->GetShared() ? 'S' : 'N', pszDriverName, (int)psStruct->nPID, poDS->GetRasterXSize(), poDS->GetRasterYSize(), poDS->GetRasterCount(), poDS->GetDescription() ); return TRUE; } static int GDALDumpOpenDatasetsForeach(void* elt, void* user_data) { DatasetCtxt* psStruct = (DatasetCtxt*) elt; FILE *fp = (FILE*) user_data; const char *pszDriverName; GDALDataset *poDS = psStruct->poDS; /* Don't list shared datasets. They have already been listed by */ /* GDALDumpOpenSharedDatasetsForeach */ if (poDS->GetShared()) return TRUE; if( poDS->GetDriver() == NULL ) pszDriverName = "DriverIsNULL"; else pszDriverName = poDS->GetDriver()->GetDescription(); poDS->Reference(); VSIFPrintf( fp, " %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(), poDS->GetShared() ? 'S' : 'N', pszDriverName, -1, poDS->GetRasterXSize(), poDS->GetRasterYSize(), poDS->GetRasterCount(), poDS->GetDescription() ); return TRUE; } /** * \brief 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 primarily 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 ) { VALIDATE_POINTER1( fp, "GDALDumpOpenDatasets", 0 ); CPLMutexHolderD( &hDLMutex ); if (phAllDatasetSet != NULL) { VSIFPrintf( fp, "Open GDAL Datasets:\n" ); CPLHashSetForeach(phAllDatasetSet, GDALDumpOpenDatasetsForeach, fp); if (phSharedDatasetSet != NULL) { CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach, fp); } return CPLHashSetSize(phAllDatasetSet); } else { return 0; } } /************************************************************************/ /* BeginAsyncReader() */ /************************************************************************/ /** * \brief Sets up an asynchronous data request * * This method establish an asynchronous raster read request for the * indicated window on the dataset into the indicated buffer. The parameters * for windowing, buffer size, buffer type and buffer organization are similar * to those for GDALDataset::RasterIO(); however, this call only launches * the request and filling the buffer is accomplished via calls to * GetNextUpdatedRegion() on the return GDALAsyncReader session object. * * Once all processing for the created session is complete, or if no further * refinement of the request is required, the GDALAsyncReader object should * be destroyed with the GDALDataset::EndAsyncReader() method. * * Note that the data buffer (pData) will potentially continue to be * updated as long as the session lives, but it is not deallocated when * the session (GDALAsyncReader) is destroyed with EndAsyncReader(). It * should be deallocated by the application at that point. * * Additional information on asynchronous IO in GDAL may be found at: * http://trac.osgeo.org/gdal/wiki/rfc24_progressive_data_support * * This method is the same as the C GDALBeginAsyncReader() function. * * @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 pBuf The buffer into which the data should be read. 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. * * @param papszOptions Driver specific control options in a string list or NULL. * Consult driver documentation for options supported. * * @return The GDALAsyncReader object representing the request. */ GDALAsyncReader* GDALDataset::BeginAsyncReader(int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount, int* panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace, char **papszOptions) { // See gdaldefaultasync.cpp return GDALGetDefaultAsyncReader( this, nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, papszOptions ); } /************************************************************************/ /* GDALBeginAsyncReader() */ /************************************************************************/ GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(GDALDatasetH hDS, int xOff, int yOff, int xSize, int ySize, void *pBuf, int bufXSize, int bufYSize, GDALDataType bufType, int nBandCount, int* bandMap, int nPixelSpace, int nLineSpace, int nBandSpace, char **papszOptions) { VALIDATE_POINTER1( hDS, "GDALDataset", NULL ); return (GDALAsyncReaderH)((GDALDataset *) hDS)-> BeginAsyncReader(xOff, yOff, xSize, ySize, pBuf, bufXSize, bufYSize, bufType, nBandCount, bandMap, nPixelSpace, nLineSpace, nBandSpace, papszOptions); } /************************************************************************/ /* EndAsyncReader() */ /************************************************************************/ /** * End asynchronous request. * * This method destroys an asynchronous io request and recovers all * resources associated with it. * * This method is the same as the C function GDALEndAsyncReader(). * * @param poARIO pointer to a GDALAsyncReader */ void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO ) { delete poARIO; } /************************************************************************/ /* GDALEndAsyncReader() */ /************************************************************************/ void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS, GDALAsyncReaderH hAsyncReaderH) { VALIDATE_POINTER0( hDS, "GDALDataset" ); VALIDATE_POINTER0( hAsyncReaderH, "GDALAsyncReader" ); ((GDALDataset *) hDS) -> EndAsyncReader((GDALAsyncReader *)hAsyncReaderH); } /************************************************************************/ /* CloseDependentDatasets() */ /************************************************************************/ /** * Drop references to any other datasets referenced by this dataset. * * This method should release any reference to other datasets (e.g. a VRT * dataset to its sources), but not close the current dataset itself. * * If at least, one reference to a dependent dataset has been dropped, * this method should return TRUE. Otherwise it *should* return FALSE. * (Failure to return the proper value might result in infinite loop) * * This method can be called several times on a given dataset. After * the first time, it should not do anything and return FALSE. * * The driver implementation may choose to destroy its raster bands, * so be careful not to call any method on the raster bands afterwards. * * Basically the only safe action you can do after calling CloseDependantDatasets() * is to call the destructor. * * Note: the only legitimate caller of CloseDependantDatasets() is * GDALDriverManager::~GDALDriverManager() * * @return TRUE if at least one reference to another dataset has been dropped. */ int GDALDataset::CloseDependentDatasets() { return oOvManager.CloseDependentDatasets(); } /************************************************************************/ /* ReportError() */ /************************************************************************/ /** * \brief Emits an error related to a dataset. * * This function is a wrapper for regular CPLError(). The only difference * with CPLError() is that it prepends the error message with the dataset * name. * * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal. * @param err_no the error number (CPLE_*) from cpl_error.h. * @param fmt a printf() style format string. Any additional arguments * will be treated as arguments to fill in this format in a manner * similar to printf(). * * @since GDAL 1.9.0 */ void GDALDataset::ReportError(CPLErr eErrClass, int err_no, const char *fmt, ...) { va_list args; va_start(args, fmt); char szNewFmt[256]; const char* pszDSName = GetDescription(); if (strlen(fmt) + strlen(pszDSName) + 3 >= sizeof(szNewFmt) - 1) pszDSName = CPLGetFilename(pszDSName); if (pszDSName[0] != '\0' && strlen(fmt) + strlen(pszDSName) + 3 < sizeof(szNewFmt) - 1) { snprintf(szNewFmt, sizeof(szNewFmt), "%s: %s", pszDSName, fmt); CPLErrorV( eErrClass, err_no, szNewFmt, args ); } else { CPLErrorV( eErrClass, err_no, fmt, args ); } va_end(args); }