LCOV - code coverage report
Current view: directory - gcore - gdalpamdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 526 475 90.3 %
Date: 2012-12-26 Functions: 34 31 91.2 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdalpamdataset.cpp 22922 2011-08-10 21:50:46Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL Core
       5                 :  * Purpose:  Implementation of GDALPamDataset, a dataset base class that 
       6                 :  *           knows how to persist auxilary metadata into a support XML file.
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "gdal_pam.h"
      32                 : #include "cpl_string.h"
      33                 : #include "ogr_spatialref.h"
      34                 : 
      35                 : CPL_CVSID("$Id: gdalpamdataset.cpp 22922 2011-08-10 21:50:46Z rouault $");
      36                 : 
      37                 : /************************************************************************/
      38                 : /*                           GDALPamDataset()                           */
      39                 : /************************************************************************/
      40                 : 
      41                 : /**
      42                 :  * \class GDALPamDataset "gdal_pam.h"
      43                 :  * 
      44                 :  * A subclass of GDALDataset which introduces the ability to save and
      45                 :  * restore auxilary information (coordinate system, gcps, metadata, 
      46                 :  * etc) not supported by a file format via an "auxilary metadata" file
      47                 :  * with the .aux.xml extension.  
      48                 :  * 
      49                 :  * <h3>Enabling PAM</h3>
      50                 :  * 
      51                 :  * PAM support can be enabled (resp. disabled) in GDAL by setting the GDAL_PAM_ENABLED
      52                 :  * configuration option (via CPLSetConfigOption(), or the environment) to 
      53                 :  * the value of YES (resp. NO). Note: The default value is build dependant and defaults
      54                 :  * to YES in Windows and Unix builds.
      55                 :  *
      56                 :  * <h3>PAM Proxy Files</h3>
      57                 :  * 
      58                 :  * In order to be able to record auxilary information about files on 
      59                 :  * read-only media such as CDROMs or in directories where the user does not
      60                 :  * have write permissions, it is possible to enable the "PAM Proxy Database".
      61                 :  * When enabled the .aux.xml files are kept in a different directory, writable
      62                 :  * by the user. Overviews will also be stored in the PAM proxy directory.
      63                 :  *
      64                 :  * To enable this, set the GDAL_PAM_PROXY_DIR configuration option to be
      65                 :  * the name of the directory where the proxies should be kept. The configuration
      66                 :  * option must be set *before* the first access to PAM, because its value is cached
      67                 :  * for later access.
      68                 :  *
      69                 :  * <h3>Adding PAM to Drivers</h3>
      70                 :  *
      71                 :  * Drivers for physical file formats that wish to support persistent auxilary 
      72                 :  * metadata in addition to that for the format itself should derive their 
      73                 :  * dataset class from GDALPamDataset instead of directly from GDALDataset.
      74                 :  * The raster band classes should also be derived from GDALPamRasterBand.
      75                 :  *
      76                 :  * They should also call something like this near the end of the Open() 
      77                 :  * method:
      78                 :  * 
      79                 :  * \code
      80                 :  *      poDS->SetDescription( poOpenInfo->pszFilename );
      81                 :  *      poDS->TryLoadXML();
      82                 :  * \endcode
      83                 :  *
      84                 :  * The SetDescription() is necessary so that the dataset will have a valid
      85                 :  * filename set as the description before TryLoadXML() is called.  TryLoadXML()
      86                 :  * will look for an .aux.xml file with the same basename as the dataset and
      87                 :  * in the same directory.  If found the contents will be loaded and kept
      88                 :  * track of in the GDALPamDataset and GDALPamRasterBand objects.  When a 
      89                 :  * call like GetProjectionRef() is not implemented by the format specific
      90                 :  * class, it will fall through to the PAM implementation which will return
      91                 :  * information if it was in the .aux.xml file. 
      92                 :  *
      93                 :  * Drivers should also try to call the GDALPamDataset/GDALPamRasterBand
      94                 :  * methods as a fallback if their implementation does not find information.
      95                 :  * This allows using the .aux.xml for variations that can't be stored in
      96                 :  * the format.  For instance, the GeoTIFF driver GetProjectionRef() looks
      97                 :  * like this:
      98                 :  *
      99                 :  * \code
     100                 :  *      if( EQUAL(pszProjection,"") )
     101                 :  *          return GDALPamDataset::GetProjectionRef();
     102                 :  *      else
     103                 :  *          return( pszProjection );
     104                 :  * \endcode
     105                 :  *
     106                 :  * So if the geotiff header is missing, the .aux.xml file will be 
     107                 :  * consulted. 
     108                 :  *
     109                 :  * Similarly, if SetProjection() were called with a coordinate system
     110                 :  * not supported by GeoTIFF, the SetProjection() method should pass it on
     111                 :  * to the GDALPamDataset::SetProjection() method after issuing a warning
     112                 :  * that the information can't be represented within the file itself. 
     113                 :  * 
     114                 :  * Drivers for subdataset based formats will also need to declare the
     115                 :  * name of the physical file they are related to, and the name of their 
     116                 :  * subdataset before calling TryLoadXML(). 
     117                 :  *
     118                 :  * \code
     119                 :  *      poDS->SetDescription( poOpenInfo->pszFilename );
     120                 :  *      poDS->SetPhysicalFilename( poDS->pszFilename );
     121                 :  *      poDS->SetSubdatasetName( osSubdatasetName );
     122                 :  * 
     123                 :  *      poDS->TryLoadXML();
     124                 :  * \endcode
     125                 :  */
     126                 : 
     127            9959 : GDALPamDataset::GDALPamDataset()
     128                 : 
     129                 : {
     130            9959 :     nPamFlags = 0;
     131            9959 :     psPam = NULL;
     132            9959 :     SetMOFlags( GetMOFlags() | GMO_PAM_CLASS );
     133            9959 : }
     134                 : 
     135                 : /************************************************************************/
     136                 : /*                          ~GDALPamDataset()                           */
     137                 : /************************************************************************/
     138                 : 
     139            9959 : GDALPamDataset::~GDALPamDataset()
     140                 : 
     141                 : {
     142            9959 :     if( nPamFlags & GPF_DIRTY )
     143                 :     {
     144             363 :         CPLDebug( "GDALPamDataset", "In destructor with dirty metadata." );
     145             363 :         FlushCache();
     146                 :     }
     147                 : 
     148            9959 :     PamClear();
     149            9959 : }
     150                 : 
     151                 : /************************************************************************/
     152                 : /*                             FlushCache()                             */
     153                 : /************************************************************************/
     154                 : 
     155           15051 : void GDALPamDataset::FlushCache()
     156                 : 
     157                 : {
     158           15051 :     GDALDataset::FlushCache();
     159           15051 :     if( nPamFlags & GPF_DIRTY )
     160            1026 :         TrySaveXML();
     161           15051 : }
     162                 : 
     163                 : /************************************************************************/
     164                 : /*                           SerializeToXML()                           */
     165                 : /************************************************************************/
     166                 : 
     167             742 : CPLXMLNode *GDALPamDataset::SerializeToXML( const char *pszUnused )
     168                 : 
     169                 : {
     170             742 :     CPLString oFmt;
     171                 : 
     172             742 :     if( psPam == NULL )
     173               0 :         return NULL;
     174                 : 
     175                 : /* -------------------------------------------------------------------- */
     176                 : /*      Setup root node and attributes.                                 */
     177                 : /* -------------------------------------------------------------------- */
     178                 :     CPLXMLNode *psDSTree;
     179                 : 
     180             742 :     psDSTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMDataset" );
     181                 : 
     182                 : /* -------------------------------------------------------------------- */
     183                 : /*      SRS                                                             */
     184                 : /* -------------------------------------------------------------------- */
     185             742 :     if( psPam->pszProjection != NULL && strlen(psPam->pszProjection) > 0 )
     186             283 :         CPLSetXMLValue( psDSTree, "SRS", psPam->pszProjection );
     187                 : 
     188                 : /* -------------------------------------------------------------------- */
     189                 : /*      GeoTransform.                                                   */
     190                 : /* -------------------------------------------------------------------- */
     191             742 :     if( psPam->bHaveGeoTransform )
     192                 :     {
     193                 :         CPLSetXMLValue( psDSTree, "GeoTransform", 
     194                 :                         oFmt.Printf( "%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
     195                 :                                      psPam->adfGeoTransform[0],
     196                 :                                      psPam->adfGeoTransform[1],
     197                 :                                      psPam->adfGeoTransform[2],
     198                 :                                      psPam->adfGeoTransform[3],
     199                 :                                      psPam->adfGeoTransform[4],
     200             193 :                                      psPam->adfGeoTransform[5] ) );
     201                 :     }
     202                 : 
     203                 : /* -------------------------------------------------------------------- */
     204                 : /*      Metadata.                                                       */
     205                 : /* -------------------------------------------------------------------- */
     206                 :     CPLXMLNode *psMD;
     207                 : 
     208             742 :     psMD = oMDMD.Serialize();
     209             742 :     if( psMD != NULL )
     210                 :     {
     211             568 :         if( psMD->psChild == NULL && psMD->psNext == NULL )
     212              20 :             CPLDestroyXMLNode( psMD );
     213                 :         else
     214             528 :             CPLAddXMLChild( psDSTree, psMD );
     215                 :     }
     216                 : 
     217                 : /* -------------------------------------------------------------------- */
     218                 : /*      GCPs                                                            */
     219                 : /* -------------------------------------------------------------------- */
     220             742 :     if( psPam->nGCPCount > 0 )
     221                 :     {
     222                 :         CPLXMLNode *psPamGCPList = CPLCreateXMLNode( psDSTree, CXT_Element, 
     223               1 :                                                      "GCPList" );
     224                 : 
     225               1 :         CPLXMLNode* psLastChild = NULL;
     226                 : 
     227               1 :         if( psPam->pszGCPProjection != NULL 
     228                 :             && strlen(psPam->pszGCPProjection) > 0 )
     229                 :         {
     230                 :             CPLSetXMLValue( psPamGCPList, "#Projection", 
     231               1 :                             psPam->pszGCPProjection );
     232               1 :             psLastChild = psPamGCPList->psChild;
     233                 :         }
     234                 : 
     235               3 :         for( int iGCP = 0; iGCP < psPam->nGCPCount; iGCP++ )
     236                 :         {
     237                 :             CPLXMLNode *psXMLGCP;
     238               2 :             GDAL_GCP *psGCP = psPam->pasGCPList + iGCP;
     239                 : 
     240               2 :             psXMLGCP = CPLCreateXMLNode( NULL, CXT_Element, "GCP" );
     241                 : 
     242               2 :             if( psLastChild == NULL )
     243               0 :                 psPamGCPList->psChild = psXMLGCP;
     244                 :             else
     245               2 :                 psLastChild->psNext = psXMLGCP;
     246               2 :             psLastChild = psXMLGCP;
     247                 : 
     248               2 :             CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );
     249                 : 
     250               2 :             if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
     251               0 :                 CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );
     252                 : 
     253                 :             CPLSetXMLValue( psXMLGCP, "#Pixel", 
     254               2 :                             oFmt.Printf( "%.4f", psGCP->dfGCPPixel ) );
     255                 : 
     256                 :             CPLSetXMLValue( psXMLGCP, "#Line", 
     257               2 :                             oFmt.Printf( "%.4f", psGCP->dfGCPLine ) );
     258                 : 
     259                 :             CPLSetXMLValue( psXMLGCP, "#X", 
     260               2 :                             oFmt.Printf( "%.12E", psGCP->dfGCPX ) );
     261                 : 
     262                 :             CPLSetXMLValue( psXMLGCP, "#Y", 
     263               2 :                             oFmt.Printf( "%.12E", psGCP->dfGCPY ) );
     264                 : 
     265               2 :             if( psGCP->dfGCPZ != 0.0 )
     266                 :                 CPLSetXMLValue( psXMLGCP, "#GCPZ", 
     267               0 :                                 oFmt.Printf( "%.12E", psGCP->dfGCPZ ) );
     268                 :         }
     269                 :     }
     270                 : 
     271                 : /* -------------------------------------------------------------------- */
     272                 : /*      Process bands.                                                  */
     273                 : /* -------------------------------------------------------------------- */
     274                 :     int iBand;
     275                 : 
     276            1944 :     for( iBand = 0; iBand < GetRasterCount(); iBand++ )
     277                 :     {
     278                 :         CPLXMLNode *psBandTree;
     279                 : 
     280                 :         GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     281            1202 :             GetRasterBand(iBand+1);
     282                 : 
     283            1202 :         if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     284               0 :             continue;
     285                 : 
     286            1202 :         psBandTree = poBand->SerializeToXML( pszUnused );
     287                 : 
     288            1202 :         if( psBandTree != NULL )
     289             651 :             CPLAddXMLChild( psDSTree, psBandTree );
     290                 :     }
     291                 : 
     292                 : /* -------------------------------------------------------------------- */
     293                 : /*      We don't want to return anything if we had no metadata to       */
     294                 : /*      attach.                                                         */
     295                 : /* -------------------------------------------------------------------- */
     296             742 :     if( psDSTree->psChild == NULL )
     297                 :     {
     298               6 :         CPLDestroyXMLNode( psDSTree );
     299               6 :         psDSTree = NULL;
     300                 :     }
     301                 : 
     302             742 :     return psDSTree;
     303                 : }
     304                 : 
     305                 : /************************************************************************/
     306                 : /*                           PamInitialize()                            */
     307                 : /************************************************************************/
     308                 : 
     309          508770 : void GDALPamDataset::PamInitialize()
     310                 : 
     311                 : {
     312                 : #ifdef PAM_ENABLED
     313                 :     static const char *pszPamDefault = "YES";
     314                 : #else
     315                 :     static const char *pszPamDefault = "NO";
     316                 : #endif
     317                 :     
     318          508770 :     if( psPam || (nPamFlags & GPF_DISABLED) )
     319          500794 :         return;
     320                 : 
     321            7976 :     if( !CSLTestBoolean( CPLGetConfigOption( "GDAL_PAM_ENABLED", 
     322                 :                                              pszPamDefault ) ) )
     323                 :     {
     324               5 :         nPamFlags |= GPF_DISABLED;
     325               5 :         return;
     326                 :     }
     327                 : 
     328                 :     /* ERO 2011/04/13 : GPF_AUXMODE seems to be unimplemented */
     329            7971 :     if( EQUAL( CPLGetConfigOption( "GDAL_PAM_MODE", "PAM" ), "AUX") )
     330               0 :         nPamFlags |= GPF_AUXMODE;
     331                 : 
     332            7971 :     psPam = new GDALDatasetPamInfo;
     333            7971 :     psPam->pszPamFilename = NULL;
     334            7971 :     psPam->pszProjection = NULL;
     335            7971 :     psPam->bHaveGeoTransform = FALSE;
     336            7971 :     psPam->nGCPCount = 0;
     337            7971 :     psPam->pasGCPList = NULL;
     338            7971 :     psPam->pszGCPProjection = NULL;
     339                 : 
     340                 :     int iBand;
     341                 :     
     342          489072 :     for( iBand = 0; iBand < GetRasterCount(); iBand++ )
     343                 :     {
     344                 :         GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     345          481101 :             GetRasterBand(iBand+1);
     346                 :         
     347          481101 :         if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     348               9 :             continue;
     349                 : 
     350          481092 :         poBand->PamInitialize();
     351                 :     }
     352                 : }
     353                 : 
     354                 : /************************************************************************/
     355                 : /*                              PamClear()                              */
     356                 : /************************************************************************/
     357                 : 
     358            9959 : void GDALPamDataset::PamClear()
     359                 : 
     360                 : {
     361            9959 :     if( psPam )
     362                 :     {
     363            7971 :         CPLFree( psPam->pszPamFilename );
     364            7971 :         CPLFree( psPam->pszProjection );
     365            7971 :         CPLFree( psPam->pszGCPProjection );
     366            7971 :         if( psPam->nGCPCount > 0 )
     367                 :         {
     368               6 :             GDALDeinitGCPs( psPam->nGCPCount, psPam->pasGCPList );
     369               6 :             CPLFree( psPam->pasGCPList );
     370                 :         }
     371                 : 
     372            7971 :         delete psPam;
     373            7971 :         psPam = NULL;
     374                 :     }
     375            9959 : }
     376                 : 
     377                 : /************************************************************************/
     378                 : /*                              XMLInit()                               */
     379                 : /************************************************************************/
     380                 : 
     381             508 : CPLErr GDALPamDataset::XMLInit( CPLXMLNode *psTree, const char *pszUnused )
     382                 : 
     383                 : {
     384                 : /* -------------------------------------------------------------------- */
     385                 : /*      Check for an SRS node.                                          */
     386                 : /* -------------------------------------------------------------------- */
     387             508 :     if( strlen(CPLGetXMLValue(psTree, "SRS", "")) > 0 )
     388                 :     {
     389             181 :         OGRSpatialReference oSRS;
     390                 : 
     391             181 :         CPLFree( psPam->pszProjection );
     392             181 :         psPam->pszProjection = NULL;
     393                 : 
     394             181 :         if( oSRS.SetFromUserInput( CPLGetXMLValue(psTree, "SRS", "") )
     395                 :             == OGRERR_NONE )
     396             181 :             oSRS.exportToWkt( &(psPam->pszProjection) );
     397                 :     }
     398                 : 
     399                 : /* -------------------------------------------------------------------- */
     400                 : /*      Check for a GeoTransform node.                                  */
     401                 : /* -------------------------------------------------------------------- */
     402             508 :     if( strlen(CPLGetXMLValue(psTree, "GeoTransform", "")) > 0 )
     403                 :     {
     404             148 :         const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
     405                 :         char  **papszTokens;
     406                 : 
     407             148 :         papszTokens = CSLTokenizeStringComplex( pszGT, ",", FALSE, FALSE );
     408             148 :         if( CSLCount(papszTokens) != 6 )
     409                 :         {
     410                 :             CPLError( CE_Warning, CPLE_AppDefined,
     411               0 :                       "GeoTransform node does not have expected six values.");
     412                 :         }
     413                 :         else
     414                 :         {
     415            1036 :             for( int iTA = 0; iTA < 6; iTA++ )
     416             888 :                 psPam->adfGeoTransform[iTA] = atof(papszTokens[iTA]);
     417             148 :             psPam->bHaveGeoTransform = TRUE;
     418                 :         }
     419                 : 
     420             148 :         CSLDestroy( papszTokens );
     421                 :     }
     422                 : 
     423                 : /* -------------------------------------------------------------------- */
     424                 : /*      Check for GCPs.                                                 */
     425                 : /* -------------------------------------------------------------------- */
     426             508 :     CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
     427                 : 
     428             508 :     if( psGCPList != NULL )
     429                 :     {
     430                 :         CPLXMLNode *psXMLGCP;
     431               5 :         OGRSpatialReference oSRS;
     432               5 :         const char *pszRawProj = CPLGetXMLValue(psGCPList, "Projection", "");
     433                 : 
     434               5 :         CPLFree( psPam->pszGCPProjection );
     435                 : 
     436               5 :         if( strlen(pszRawProj) > 0 
     437                 :             && oSRS.SetFromUserInput( pszRawProj ) == OGRERR_NONE )
     438               5 :             oSRS.exportToWkt( &(psPam->pszGCPProjection) );
     439                 :         else
     440               0 :             psPam->pszGCPProjection = CPLStrdup("");
     441                 : 
     442                 :         // Count GCPs.
     443               5 :         int  nGCPMax = 0;
     444                 :          
     445              24 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     446                 :              psXMLGCP = psXMLGCP->psNext )
     447              19 :             nGCPMax++;
     448                 :         
     449                 :         // Make sure any previous GCPs, perhaps from an .aux file, are cleared
     450                 :         // if we have new ones.
     451               5 :         if( psPam->nGCPCount > 0 )
     452                 :         {
     453               0 :             GDALDeinitGCPs( psPam->nGCPCount, psPam->pasGCPList );
     454               0 :             CPLFree( psPam->pasGCPList );
     455               0 :             psPam->nGCPCount = 0;
     456               0 :             psPam->pasGCPList = 0;
     457                 :         }
     458                 : 
     459               5 :         psPam->pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax);
     460                 :          
     461              24 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     462                 :              psXMLGCP = psXMLGCP->psNext )
     463                 :         {
     464              19 :             GDAL_GCP *psGCP = psPam->pasGCPList + psPam->nGCPCount;
     465                 : 
     466              19 :             if( !EQUAL(psXMLGCP->pszValue,"GCP") || 
     467                 :                 psXMLGCP->eType != CXT_Element )
     468               5 :                 continue;
     469                 :              
     470              14 :             GDALInitGCPs( 1, psGCP );
     471                 :              
     472              14 :             CPLFree( psGCP->pszId );
     473              14 :             psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
     474                 :              
     475              14 :             CPLFree( psGCP->pszInfo );
     476              14 :             psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
     477                 :              
     478              14 :             psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
     479              14 :             psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
     480                 :              
     481              14 :             psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
     482              14 :             psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
     483              14 :             psGCP->dfGCPZ = atof(CPLGetXMLValue(psXMLGCP,"Z","0.0"));
     484                 : 
     485              14 :             psPam->nGCPCount++;
     486               5 :         }
     487                 :     }
     488                 : 
     489                 : /* -------------------------------------------------------------------- */
     490                 : /*      Apply any dataset level metadata.                               */
     491                 : /* -------------------------------------------------------------------- */
     492             508 :     oMDMD.XMLInit( psTree, TRUE );
     493                 : 
     494                 : /* -------------------------------------------------------------------- */
     495                 : /*      Try loading ESRI xml encoded projection                         */
     496                 : /* -------------------------------------------------------------------- */
     497             508 :     if (psPam->pszProjection == NULL)
     498                 :     {
     499             327 :         char** papszXML = oMDMD.GetMetadata( "xml:ESRI" );
     500             327 :         if (CSLCount(papszXML) == 1)
     501                 :         {
     502               6 :             CPLXMLNode *psValueAsXML = CPLParseXMLString( papszXML[0] );
     503               6 :             if (psValueAsXML)
     504                 :             {
     505                 :                 const char* pszESRI_WKT = CPLGetXMLValue(psValueAsXML,
     506               6 :                                   "=GeodataXform.SpatialReference.WKT", NULL);
     507               6 :                 if (pszESRI_WKT)
     508                 :                 {
     509               2 :                     OGRSpatialReference* poSRS = new OGRSpatialReference(NULL);
     510               2 :                     char* pszTmp = (char*)pszESRI_WKT;
     511               4 :                     if (poSRS->importFromWkt(&pszTmp) == OGRERR_NONE &&
     512                 :                         poSRS->morphFromESRI() == OGRERR_NONE)
     513                 :                     {
     514               2 :                         char* pszWKT = NULL;
     515               2 :                         if (poSRS->exportToWkt(&pszWKT) == OGRERR_NONE)
     516                 :                         {
     517               2 :                             psPam->pszProjection = CPLStrdup(pszWKT);
     518                 :                         }
     519               2 :                         CPLFree(pszWKT);
     520                 :                     }
     521               2 :                     delete poSRS;
     522                 :                 }
     523               6 :                 CPLDestroyXMLNode(psValueAsXML);
     524                 :             }
     525                 :         }
     526                 :     }
     527                 : 
     528                 : /* -------------------------------------------------------------------- */
     529                 : /*      Process bands.                                                  */
     530                 : /* -------------------------------------------------------------------- */
     531                 :     CPLXMLNode *psBandTree;
     532                 : 
     533            1609 :     for( psBandTree = psTree->psChild; 
     534                 :          psBandTree != NULL; psBandTree = psBandTree->psNext )
     535                 :     {
     536            1101 :         if( psBandTree->eType != CXT_Element
     537                 :             || !EQUAL(psBandTree->pszValue,"PAMRasterBand") )
     538             666 :             continue;
     539                 : 
     540             435 :         int nBand = atoi(CPLGetXMLValue( psBandTree, "band", "0"));
     541                 : 
     542             435 :         if( nBand < 1 || nBand > GetRasterCount() )
     543               1 :             continue;
     544                 : 
     545                 :         GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     546             434 :             GetRasterBand(nBand);
     547                 : 
     548             434 :         if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     549               0 :             continue;
     550                 : 
     551             434 :         poBand->XMLInit( psBandTree, pszUnused );
     552                 :     }
     553                 : 
     554                 : /* -------------------------------------------------------------------- */
     555                 : /*      Clear dirty flag.                                               */
     556                 : /* -------------------------------------------------------------------- */
     557             508 :     nPamFlags &= ~GPF_DIRTY;
     558                 : 
     559             508 :     return CE_None;
     560                 : }
     561                 : 
     562                 : /************************************************************************/
     563                 : /*                        SetPhysicalFilename()                         */
     564                 : /************************************************************************/
     565                 : 
     566             340 : void GDALPamDataset::SetPhysicalFilename( const char *pszFilename )
     567                 : 
     568                 : {
     569             340 :     PamInitialize();
     570                 : 
     571             340 :     if( psPam )
     572             340 :         psPam->osPhysicalFilename = pszFilename;
     573             340 : }
     574                 : 
     575                 : /************************************************************************/
     576                 : /*                        GetPhysicalFilename()                         */
     577                 : /************************************************************************/
     578                 : 
     579              24 : const char *GDALPamDataset::GetPhysicalFilename()
     580                 : 
     581                 : {
     582              24 :     PamInitialize();
     583                 : 
     584              24 :     if( psPam )
     585              24 :         return psPam->osPhysicalFilename;
     586                 :     else
     587               0 :         return "";
     588                 : }
     589                 : 
     590                 : /************************************************************************/
     591                 : /*                         SetSubdatasetName()                          */
     592                 : /************************************************************************/
     593                 : 
     594             340 : void GDALPamDataset::SetSubdatasetName( const char *pszSubdataset )
     595                 : 
     596                 : {
     597             340 :     PamInitialize();
     598                 : 
     599             340 :     if( psPam )
     600             340 :         psPam->osSubdatasetName = pszSubdataset;
     601             340 : }
     602                 : 
     603                 : /************************************************************************/
     604                 : /*                         GetSubdatasetName()                          */
     605                 : /************************************************************************/
     606                 : 
     607              10 : const char *GDALPamDataset::GetSubdatasetName()
     608                 : 
     609                 : {
     610              10 :     PamInitialize();
     611                 : 
     612              10 :     if( psPam )
     613              10 :         return psPam->osSubdatasetName;
     614                 :     else
     615               0 :         return "";
     616                 : }
     617                 : 
     618                 : /************************************************************************/
     619                 : /*                          BuildPamFilename()                          */
     620                 : /************************************************************************/
     621                 : 
     622            8303 : const char *GDALPamDataset::BuildPamFilename()
     623                 : 
     624                 : {
     625            8303 :     if( psPam == NULL )
     626              20 :         return NULL;
     627                 : 
     628                 : /* -------------------------------------------------------------------- */
     629                 : /*      What is the name of the physical file we are referencing?       */
     630                 : /*      We allow an override via the psPam->pszPhysicalFile item.       */
     631                 : /* -------------------------------------------------------------------- */
     632            8283 :     if( psPam->pszPamFilename != NULL )
     633             610 :         return psPam->pszPamFilename;
     634                 : 
     635            7673 :     const char *pszPhysicalFile = psPam->osPhysicalFilename;
     636                 : 
     637            7673 :     if( strlen(pszPhysicalFile) == 0 && GetDescription() != NULL )
     638            7339 :         pszPhysicalFile = GetDescription();
     639                 : 
     640            7673 :     if( strlen(pszPhysicalFile) == 0 )
     641               7 :         return NULL;
     642                 : 
     643                 : /* -------------------------------------------------------------------- */
     644                 : /*      Try a proxy lookup, otherwise just add .aux.xml.                */
     645                 : /* -------------------------------------------------------------------- */
     646            7666 :     const char *pszProxyPam = PamGetProxy( pszPhysicalFile );
     647            7666 :     if( pszProxyPam != NULL )
     648               4 :         psPam->pszPamFilename = CPLStrdup(pszProxyPam);
     649                 :     else
     650                 :     {
     651            7662 :         psPam->pszPamFilename = (char*) CPLMalloc(strlen(pszPhysicalFile)+10);
     652            7662 :         strcpy( psPam->pszPamFilename, pszPhysicalFile );
     653            7662 :         strcat( psPam->pszPamFilename, ".aux.xml" );
     654                 :     }
     655                 : 
     656            7666 :     return psPam->pszPamFilename;
     657                 : }
     658                 : 
     659                 : /************************************************************************/
     660                 : /*                   IsPamFilenameAPotentialSiblingFile()               */
     661                 : /************************************************************************/
     662                 : 
     663            4834 : int GDALPamDataset::IsPamFilenameAPotentialSiblingFile()
     664                 : {
     665            4834 :     if (psPam == NULL)
     666               0 :         return FALSE;
     667                 : 
     668                 : /* -------------------------------------------------------------------- */
     669                 : /*      Determine if the PAM filename is a .aux.xml file next to the    */
     670                 : /*      physical file, or if it comes from the ProxyDB                  */
     671                 : /* -------------------------------------------------------------------- */
     672            4834 :     const char *pszPhysicalFile = psPam->osPhysicalFilename;
     673                 : 
     674            4834 :     if( strlen(pszPhysicalFile) == 0 && GetDescription() != NULL )
     675            4834 :         pszPhysicalFile = GetDescription();
     676                 : 
     677            4834 :     int nLenPhysicalFile = strlen(pszPhysicalFile);
     678                 :     int bIsSiblingPamFile = strncmp(psPam->pszPamFilename, pszPhysicalFile,
     679                 :                                     nLenPhysicalFile) == 0 &&
     680                 :                             strcmp(psPam->pszPamFilename + nLenPhysicalFile,
     681            4834 :                                    ".aux.xml") == 0;
     682                 : 
     683            4834 :     return bIsSiblingPamFile;
     684                 : }
     685                 : 
     686                 : /************************************************************************/
     687                 : /*                             TryLoadXML()                             */
     688                 : /************************************************************************/
     689                 : 
     690            7552 : CPLErr GDALPamDataset::TryLoadXML(char **papszSiblingFiles)
     691                 : 
     692                 : {
     693            7552 :     CPLXMLNode *psTree = NULL;
     694                 : 
     695            7552 :     PamInitialize();
     696                 : 
     697                 : /* -------------------------------------------------------------------- */
     698                 : /*      Clear dirty flag.  Generally when we get to this point is       */
     699                 : /*      from a call at the end of the Open() method, and some calls     */
     700                 : /*      may have already marked the PAM info as dirty (for instance     */
     701                 : /*      setting metadata), but really everything to this point is       */
     702                 : /*      reproducable, and so the PAM info shouldn't really be           */
     703                 : /*      thought of as dirty.                                            */
     704                 : /* -------------------------------------------------------------------- */
     705            7552 :     nPamFlags &= ~GPF_DIRTY;
     706                 : 
     707                 : /* -------------------------------------------------------------------- */
     708                 : /*      Try reading the file.                                           */
     709                 : /* -------------------------------------------------------------------- */
     710            7552 :     if( !BuildPamFilename() )
     711              20 :         return CE_None;
     712                 : 
     713                 :     VSIStatBufL sStatBuf;
     714                 : 
     715                 : /* -------------------------------------------------------------------- */
     716                 : /*      In case the PAM filename is a .aux.xml file next to the         */
     717                 : /*      physical file and we have a siblings list, then we can skip     */
     718                 : /*      stat'ing the filesystem.                                        */
     719                 : /* -------------------------------------------------------------------- */
     720            7532 :     if (papszSiblingFiles != NULL && IsPamFilenameAPotentialSiblingFile())
     721                 :     {
     722                 :         int iSibling = CSLFindString( papszSiblingFiles,
     723            3788 :                                       CPLGetFilename(psPam->pszPamFilename) );
     724            3788 :         if( iSibling >= 0 )
     725                 :         {
     726             109 :             CPLErrorReset();
     727             109 :             CPLPushErrorHandler( CPLQuietErrorHandler );
     728             109 :             psTree = CPLParseXMLFile( psPam->pszPamFilename );
     729             109 :             CPLPopErrorHandler();
     730                 :         }
     731                 :     }
     732                 :     else
     733            3744 :     if( VSIStatExL( psPam->pszPamFilename, &sStatBuf,
     734                 :                     VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0
     735                 :         && VSI_ISREG( sStatBuf.st_mode ) )
     736                 :     {
     737             501 :         CPLErrorReset();
     738             501 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     739             501 :         psTree = CPLParseXMLFile( psPam->pszPamFilename );
     740             501 :         CPLPopErrorHandler();
     741                 :     }
     742                 : 
     743                 : /* -------------------------------------------------------------------- */
     744                 : /*      If we are looking for a subdataset, search for it's subtree     */
     745                 : /*      now.                                                            */
     746                 : /* -------------------------------------------------------------------- */
     747            7532 :     if( psTree && psPam->osSubdatasetName.size() )
     748                 :     {
     749                 :         CPLXMLNode *psSubTree;
     750                 :         
     751             205 :         for( psSubTree = psTree->psChild; 
     752                 :              psSubTree != NULL;
     753                 :              psSubTree = psSubTree->psNext )
     754                 :         {
     755             105 :             if( psSubTree->eType != CXT_Element
     756                 :                 || !EQUAL(psSubTree->pszValue,"Subdataset") )
     757              96 :                 continue;
     758                 : 
     759               9 :             if( !EQUAL(CPLGetXMLValue( psSubTree, "name", "" ),
     760                 :                        psPam->osSubdatasetName) )
     761               4 :                 continue;
     762                 : 
     763               5 :             psSubTree = CPLGetXMLNode( psSubTree, "PAMDataset" );
     764               5 :             break;
     765                 :         }
     766                 :         
     767             105 :         if( psSubTree != NULL )
     768               5 :             psSubTree = CPLCloneXMLTree( psSubTree );
     769                 : 
     770             105 :         CPLDestroyXMLNode( psTree );
     771             105 :         psTree = psSubTree;
     772                 :     }
     773                 : 
     774                 : /* -------------------------------------------------------------------- */
     775                 : /*      If we fail, try .aux.                                           */
     776                 : /* -------------------------------------------------------------------- */
     777            7532 :     if( psTree == NULL )
     778            7024 :         return TryLoadAux(papszSiblingFiles);
     779                 : 
     780                 : /* -------------------------------------------------------------------- */
     781                 : /*      Initialize ourselves from this XML tree.                        */
     782                 : /* -------------------------------------------------------------------- */
     783                 :     CPLErr eErr;
     784                 : 
     785             508 :     CPLString osVRTPath(CPLGetPath(psPam->pszPamFilename));
     786             508 :     eErr = XMLInit( psTree, osVRTPath );
     787                 : 
     788             508 :     CPLDestroyXMLNode( psTree );
     789                 : 
     790             508 :     if( eErr != CE_None )
     791               0 :         PamClear();
     792                 : 
     793             508 :     return eErr;
     794                 : }
     795                 : 
     796                 : /************************************************************************/
     797                 : /*                             TrySaveXML()                             */
     798                 : /************************************************************************/
     799                 : 
     800            1027 : CPLErr GDALPamDataset::TrySaveXML()
     801                 : 
     802                 : {
     803                 :     CPLXMLNode *psTree;
     804            1027 :     CPLErr eErr = CE_None;
     805                 : 
     806            1027 :     nPamFlags &= ~GPF_DIRTY;
     807                 : 
     808            1027 :     if( psPam == NULL || (nPamFlags & GPF_NOSAVE) )
     809             276 :         return CE_None;
     810                 : 
     811                 : /* -------------------------------------------------------------------- */
     812                 : /*      Make sure we know the filename we want to store in.             */
     813                 : /* -------------------------------------------------------------------- */
     814             751 :     if( !BuildPamFilename() )
     815               7 :         return CE_None;
     816                 : 
     817                 : /* -------------------------------------------------------------------- */
     818                 : /*      Build the XML representation of the auxilary metadata.          */
     819                 : /* -------------------------------------------------------------------- */
     820             744 :     psTree = SerializeToXML( NULL );
     821                 : 
     822             744 :     if( psTree == NULL )
     823                 :     {
     824                 :         /* If we have unset all metadata, we have to delete the PAM file */
     825               8 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     826               8 :         VSIUnlink(psPam->pszPamFilename);
     827               8 :         CPLPopErrorHandler();
     828               8 :         return CE_None;
     829                 :     }
     830                 : 
     831                 : /* -------------------------------------------------------------------- */
     832                 : /*      If we are working with a subdataset, we need to integrate       */
     833                 : /*      the subdataset tree within the whole existing pam tree,         */
     834                 : /*      after removing any old version of the same subdataset.          */
     835                 : /* -------------------------------------------------------------------- */
     836             736 :     if( psPam->osSubdatasetName.size() != 0 )
     837                 :     {
     838                 :         CPLXMLNode *psOldTree, *psSubTree;
     839                 : 
     840               4 :         CPLErrorReset();
     841               4 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     842               4 :         psOldTree = CPLParseXMLFile( psPam->pszPamFilename );
     843               4 :         CPLPopErrorHandler();
     844                 : 
     845               4 :         if( psOldTree == NULL )
     846               4 :             psOldTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMDataset" );
     847                 : 
     848               4 :         for( psSubTree = psOldTree->psChild; 
     849                 :              psSubTree != NULL;
     850                 :              psSubTree = psSubTree->psNext )
     851                 :         {
     852               0 :             if( psSubTree->eType != CXT_Element
     853                 :                 || !EQUAL(psSubTree->pszValue,"Subdataset") )
     854               0 :                 continue;
     855                 : 
     856               0 :             if( !EQUAL(CPLGetXMLValue( psSubTree, "name", "" ),
     857                 :                        psPam->osSubdatasetName) )
     858               0 :                 continue;
     859                 : 
     860               0 :             break;
     861                 :         }
     862                 : 
     863               4 :         if( psSubTree == NULL )
     864                 :         {
     865                 :             psSubTree = CPLCreateXMLNode( psOldTree, CXT_Element, 
     866               4 :                                           "Subdataset" );
     867                 :             CPLCreateXMLNode( 
     868                 :                 CPLCreateXMLNode( psSubTree, CXT_Attribute, "name" ),
     869               4 :                 CXT_Text, psPam->osSubdatasetName );
     870                 :         }
     871                 :         
     872               4 :         CPLXMLNode *psOldPamDataset = CPLGetXMLNode( psSubTree, "PAMDataset");
     873               4 :         if( psOldPamDataset != NULL )
     874                 :         {
     875               0 :             CPLRemoveXMLChild( psSubTree, psOldPamDataset );
     876               0 :             CPLDestroyXMLNode( psOldPamDataset );
     877                 :         }
     878                 : 
     879               4 :         CPLAddXMLChild( psSubTree, psTree );
     880               4 :         psTree = psOldTree;
     881                 :     }
     882                 : 
     883                 : /* -------------------------------------------------------------------- */
     884                 : /*      Try saving the auxilary metadata.                               */
     885                 : /* -------------------------------------------------------------------- */
     886                 :     int bSaved;
     887                 :     
     888             736 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     889             736 :     bSaved = CPLSerializeXMLTreeToFile( psTree, psPam->pszPamFilename );
     890             736 :     CPLPopErrorHandler();
     891                 : 
     892                 : /* -------------------------------------------------------------------- */
     893                 : /*      If it fails, check if we have a proxy directory for auxilary    */
     894                 : /*      metadata to be stored in, and try to save there.                */
     895                 : /* -------------------------------------------------------------------- */
     896             736 :     if( bSaved )
     897             733 :         eErr = CE_None;
     898                 :     else
     899                 :     {
     900                 :         const char *pszNewPam;
     901               3 :         const char *pszBasename = GetDescription();
     902                 : 
     903               3 :         if( psPam && psPam->osPhysicalFilename.length() > 0 )
     904               0 :             pszBasename = psPam->osPhysicalFilename;
     905                 :             
     906               3 :         if( PamGetProxy(pszBasename) == NULL 
     907                 :             && ((pszNewPam = PamAllocateProxy(pszBasename)) != NULL))
     908                 :         {
     909               1 :             CPLErrorReset();
     910               1 :             CPLFree( psPam->pszPamFilename );
     911               1 :             psPam->pszPamFilename = CPLStrdup(pszNewPam);
     912               1 :             eErr = TrySaveXML();
     913                 :         }
     914                 :         else
     915                 :         {
     916                 :             CPLError( CE_Warning, CPLE_AppDefined, 
     917                 :                       "Unable to save auxilary information in %s.",
     918               2 :                       psPam->pszPamFilename );
     919               2 :             eErr = CE_Warning;
     920                 :         }
     921                 :     }
     922                 :     
     923                 : /* -------------------------------------------------------------------- */
     924                 : /*      Cleanup                                                         */
     925                 : /* -------------------------------------------------------------------- */
     926             736 :     CPLDestroyXMLNode( psTree );
     927                 : 
     928             736 :     return eErr;
     929                 : }
     930                 : 
     931                 : /************************************************************************/
     932                 : /*                             CloneInfo()                              */
     933                 : /************************************************************************/
     934                 : 
     935             604 : CPLErr GDALPamDataset::CloneInfo( GDALDataset *poSrcDS, int nCloneFlags )
     936                 : 
     937                 : {
     938             604 :     int bOnlyIfMissing = nCloneFlags & GCIF_ONLY_IF_MISSING;
     939             604 :     int nSavedMOFlags = GetMOFlags();
     940                 : 
     941             604 :     PamInitialize();
     942                 : 
     943                 : /* -------------------------------------------------------------------- */
     944                 : /*      Supress NotImplemented error messages - mainly needed if PAM    */
     945                 : /*      disabled.                                                       */
     946                 : /* -------------------------------------------------------------------- */
     947             604 :     SetMOFlags( nSavedMOFlags | GMO_IGNORE_UNIMPLEMENTED );
     948                 : 
     949                 : /* -------------------------------------------------------------------- */
     950                 : /*      GeoTransform                                                    */
     951                 : /* -------------------------------------------------------------------- */
     952             604 :     if( nCloneFlags & GCIF_GEOTRANSFORM )
     953                 :     {
     954                 :         double adfGeoTransform[6];
     955                 : 
     956             604 :         if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
     957                 :         {
     958                 :             double adfOldGT[6];
     959                 : 
     960             480 :             if( !bOnlyIfMissing || GetGeoTransform( adfOldGT ) != CE_None )
     961              58 :                 SetGeoTransform( adfGeoTransform );
     962                 :         }
     963                 :     }
     964                 : 
     965                 : /* -------------------------------------------------------------------- */
     966                 : /*      Projection                                                      */
     967                 : /* -------------------------------------------------------------------- */
     968             604 :     if( nCloneFlags & GCIF_PROJECTION )
     969                 :     {
     970             604 :         const char *pszWKT = poSrcDS->GetProjectionRef();
     971                 : 
     972             604 :         if( pszWKT != NULL && strlen(pszWKT) > 0 )
     973                 :         {
     974            1404 :             if( !bOnlyIfMissing 
     975             468 :                 || GetProjectionRef() == NULL
     976             468 :                 || strlen(GetProjectionRef()) == 0 )
     977             111 :                 SetProjection( pszWKT );
     978                 :         }
     979                 :     }
     980                 : 
     981                 : /* -------------------------------------------------------------------- */
     982                 : /*      GCPs                                                            */
     983                 : /* -------------------------------------------------------------------- */
     984             604 :     if( nCloneFlags & GCIF_GCPS )
     985                 :     {
     986             604 :         if( poSrcDS->GetGCPCount() > 0 )
     987                 :         {
     988               7 :             if( !bOnlyIfMissing || GetGCPCount() == 0 )
     989                 :             {
     990               1 :                 SetGCPs( poSrcDS->GetGCPCount(), 
     991               1 :                          poSrcDS->GetGCPs(), 
     992               3 :                          poSrcDS->GetGCPProjection() );
     993                 :             }
     994                 :         }
     995                 :     }
     996                 : 
     997                 : /* -------------------------------------------------------------------- */
     998                 : /*      Metadata                                                        */
     999                 : /* -------------------------------------------------------------------- */
    1000             604 :     if( nCloneFlags & GCIF_METADATA )
    1001                 :     {
    1002             604 :         if( poSrcDS->GetMetadata() != NULL )
    1003                 :         {
    1004            1359 :             if( !bOnlyIfMissing 
    1005             906 :                 || CSLCount(GetMetadata()) != CSLCount(poSrcDS->GetMetadata()) )
    1006                 :             {
    1007             226 :                 SetMetadata( poSrcDS->GetMetadata() );
    1008                 :             }
    1009                 :         }
    1010             604 :         if( poSrcDS->GetMetadata("RPC") != NULL )
    1011                 :         {
    1012              12 :             if( !bOnlyIfMissing 
    1013               4 :                 || CSLCount(GetMetadata("RPC")) 
    1014               4 :                    != CSLCount(poSrcDS->GetMetadata("RPC")) )
    1015                 :             {
    1016               0 :                 SetMetadata( poSrcDS->GetMetadata("RPC"), "RPC" );
    1017                 :             }
    1018                 :         }
    1019                 :     }
    1020                 : 
    1021                 : /* -------------------------------------------------------------------- */
    1022                 : /*      Process bands.                                                  */
    1023                 : /* -------------------------------------------------------------------- */
    1024             604 :     if( nCloneFlags & GCIF_PROCESS_BANDS )
    1025                 :     {
    1026                 :         int iBand;
    1027                 : 
    1028            1531 :         for( iBand = 0; iBand < GetRasterCount(); iBand++ )
    1029                 :         {
    1030                 :             GDALPamRasterBand *poBand = (GDALPamRasterBand *)
    1031             927 :                 GetRasterBand(iBand+1);
    1032                 : 
    1033             927 :             if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
    1034               0 :                 continue;
    1035                 : 
    1036             927 :             if( poSrcDS->GetRasterCount() >= iBand+1 )
    1037                 :                 poBand->CloneInfo( poSrcDS->GetRasterBand(iBand+1), 
    1038             927 :                                    nCloneFlags );
    1039                 :             else
    1040               0 :                 CPLDebug( "GDALPamDataset", "Skipping CloneInfo for band not in source, this is a bit unusual!" );
    1041                 :         }
    1042                 :     }
    1043                 : 
    1044                 : /* -------------------------------------------------------------------- */
    1045                 : /*      Copy masks.  These are really copied at a lower level using     */
    1046                 : /*      GDALDefaultOverviews, for formats with no native mask           */
    1047                 : /*      support but this is a convenient central point to put this      */
    1048                 : /*      for most drivers.                                               */
    1049                 : /* -------------------------------------------------------------------- */
    1050             604 :     if( nCloneFlags & GCIF_MASK )
    1051                 :     {
    1052             373 :         GDALDriver::DefaultCopyMasks( poSrcDS, this, FALSE );
    1053                 :     }
    1054                 : 
    1055                 : /* -------------------------------------------------------------------- */
    1056                 : /*      Restore MO flags.                                               */
    1057                 : /* -------------------------------------------------------------------- */
    1058             604 :     SetMOFlags( nSavedMOFlags );
    1059                 : 
    1060             604 :     return CE_None;
    1061                 : }
    1062                 : 
    1063                 : /************************************************************************/
    1064                 : /*                            GetFileList()                             */
    1065                 : /*                                                                      */
    1066                 : /*      Add .aux.xml or .aux file into file list as appropriate.        */
    1067                 : /************************************************************************/
    1068                 : 
    1069            1544 : char **GDALPamDataset::GetFileList()
    1070                 : 
    1071                 : {
    1072                 :     VSIStatBufL sStatBuf;
    1073            1544 :     char **papszFileList = GDALDataset::GetFileList();
    1074                 : 
    1075            1544 :     if( psPam && psPam->osPhysicalFilename.size() > 0
    1076                 :         && CSLFindString( papszFileList, psPam->osPhysicalFilename ) == -1 )
    1077                 :     {
    1078                 :         papszFileList = CSLInsertString( papszFileList, 0, 
    1079               0 :                                          psPam->osPhysicalFilename );
    1080                 :     }
    1081                 : 
    1082            1544 :     if( psPam && psPam->pszPamFilename )
    1083                 :     {
    1084            1543 :         int bAddPamFile = (nPamFlags & GPF_DIRTY);
    1085            1543 :         if (!bAddPamFile)
    1086                 :         {
    1087            1543 :             if (oOvManager.GetSiblingFiles() != NULL && IsPamFilenameAPotentialSiblingFile())
    1088                 :                 bAddPamFile = CSLFindString(oOvManager.GetSiblingFiles(),
    1089            1039 :                                   CPLGetFilename(psPam->pszPamFilename)) >= 0;
    1090                 :             else
    1091                 :                 bAddPamFile = VSIStatExL( psPam->pszPamFilename, &sStatBuf,
    1092             504 :                                           VSI_STAT_EXISTS_FLAG ) == 0;
    1093                 :         }
    1094            1543 :         if (bAddPamFile)
    1095                 :         {
    1096             217 :             papszFileList = CSLAddString( papszFileList, psPam->pszPamFilename );
    1097                 :         }
    1098                 :     }
    1099                 : 
    1100            1544 :     if( psPam && psPam->osAuxFilename.size() > 0 &&
    1101                 :         CSLFindString( papszFileList, psPam->osAuxFilename ) == -1 )
    1102                 :     {
    1103               0 :         papszFileList = CSLAddString( papszFileList, psPam->osAuxFilename );
    1104                 :     }
    1105            1544 :     return papszFileList;
    1106                 : }
    1107                 : 
    1108                 : /************************************************************************/
    1109                 : /*                          IBuildOverviews()                           */
    1110                 : /************************************************************************/
    1111                 : 
    1112              20 : CPLErr GDALPamDataset::IBuildOverviews( const char *pszResampling, 
    1113                 :                                         int nOverviews, int *panOverviewList, 
    1114                 :                                         int nListBands, int *panBandList,
    1115                 :                                         GDALProgressFunc pfnProgress, 
    1116                 :                                         void * pProgressData )
    1117                 :     
    1118                 : {
    1119                 : /* -------------------------------------------------------------------- */
    1120                 : /*      Initialize PAM.                                                 */
    1121                 : /* -------------------------------------------------------------------- */
    1122              20 :     PamInitialize();
    1123              20 :     if( psPam == NULL )
    1124                 :         return GDALDataset::IBuildOverviews( pszResampling,
    1125                 :                                              nOverviews, panOverviewList,
    1126                 :                                              nListBands, panBandList,
    1127               1 :                                              pfnProgress, pProgressData );
    1128                 : 
    1129                 : /* -------------------------------------------------------------------- */
    1130                 : /*      If we appear to have subdatasets and to have a physical         */
    1131                 : /*      filename, use that physical filename to derive a name for a     */
    1132                 : /*      new overview file.                                              */
    1133                 : /* -------------------------------------------------------------------- */
    1134              19 :     if( oOvManager.IsInitialized() && psPam->osPhysicalFilename.length() != 0 )
    1135                 :         return oOvManager.BuildOverviewsSubDataset( 
    1136                 :             psPam->osPhysicalFilename, pszResampling, 
    1137                 :             nOverviews, panOverviewList,
    1138                 :             nListBands, panBandList,
    1139               4 :             pfnProgress, pProgressData );
    1140                 :     else 
    1141                 :         return GDALDataset::IBuildOverviews( pszResampling, 
    1142                 :                                              nOverviews, panOverviewList, 
    1143                 :                                              nListBands, panBandList, 
    1144              15 :                                              pfnProgress, pProgressData );
    1145                 : }
    1146                 : 
    1147                 : 
    1148                 : /************************************************************************/
    1149                 : /*                          GetProjectionRef()                          */
    1150                 : /************************************************************************/
    1151                 : 
    1152            4547 : const char *GDALPamDataset::GetProjectionRef()
    1153                 : 
    1154                 : {
    1155            4547 :     if( psPam && psPam->pszProjection )
    1156              22 :         return psPam->pszProjection;
    1157                 :     else
    1158            4525 :         return GDALDataset::GetProjectionRef();
    1159                 : }
    1160                 : 
    1161                 : /************************************************************************/
    1162                 : /*                           SetProjection()                            */
    1163                 : /************************************************************************/
    1164                 : 
    1165             337 : CPLErr GDALPamDataset::SetProjection( const char *pszProjectionIn )
    1166                 : 
    1167                 : {
    1168             337 :     PamInitialize();
    1169                 : 
    1170             337 :     if( psPam == NULL )
    1171               5 :         return GDALDataset::SetProjection( pszProjectionIn );
    1172                 :     else
    1173                 :     {
    1174             332 :         CPLFree( psPam->pszProjection );
    1175             332 :         psPam->pszProjection = CPLStrdup( pszProjectionIn );
    1176             332 :         MarkPamDirty();
    1177                 : 
    1178             332 :         return CE_None;
    1179                 :     }
    1180                 : }
    1181                 : 
    1182                 : /************************************************************************/
    1183                 : /*                          GetGeoTransform()                           */
    1184                 : /************************************************************************/
    1185                 : 
    1186            4185 : CPLErr GDALPamDataset::GetGeoTransform( double * padfTransform )
    1187                 : 
    1188                 : {
    1189            4185 :     if( psPam && psPam->bHaveGeoTransform )
    1190                 :     {
    1191              54 :         memcpy( padfTransform, psPam->adfGeoTransform, sizeof(double) * 6 );
    1192              54 :         return CE_None;
    1193                 :     }
    1194                 :     else
    1195            4131 :         return GDALDataset::GetGeoTransform( padfTransform );
    1196                 : }
    1197                 : 
    1198                 : /************************************************************************/
    1199                 : /*                          SetGeoTransform()                           */
    1200                 : /************************************************************************/
    1201                 : 
    1202             198 : CPLErr GDALPamDataset::SetGeoTransform( double * padfTransform )
    1203                 : 
    1204                 : {
    1205             198 :     PamInitialize();
    1206                 : 
    1207             198 :     if( psPam )
    1208                 :     {
    1209             193 :         MarkPamDirty();
    1210             193 :         psPam->bHaveGeoTransform = TRUE;
    1211             193 :         memcpy( psPam->adfGeoTransform, padfTransform, sizeof(double) * 6 );
    1212             193 :         return( CE_None );
    1213                 :     }
    1214                 :     else
    1215                 :     {
    1216               5 :         return GDALDataset::SetGeoTransform( padfTransform );
    1217                 :     }
    1218                 : }
    1219                 : 
    1220                 : /************************************************************************/
    1221                 : /*                            GetGCPCount()                             */
    1222                 : /************************************************************************/
    1223                 : 
    1224            4012 : int GDALPamDataset::GetGCPCount()
    1225                 : 
    1226                 : {
    1227            4012 :     if( psPam && psPam->nGCPCount > 0 )
    1228               8 :         return psPam->nGCPCount;
    1229                 :     else
    1230            4004 :         return GDALDataset::GetGCPCount();
    1231                 : }
    1232                 : 
    1233                 : /************************************************************************/
    1234                 : /*                          GetGCPProjection()                          */
    1235                 : /************************************************************************/
    1236                 : 
    1237               7 : const char *GDALPamDataset::GetGCPProjection()
    1238                 : 
    1239                 : {
    1240               7 :     if( psPam && psPam->pszGCPProjection != NULL )
    1241               5 :         return psPam->pszGCPProjection;
    1242                 :     else
    1243               2 :         return GDALDataset::GetGCPProjection();
    1244                 : }
    1245                 : 
    1246                 : /************************************************************************/
    1247                 : /*                               GetGCPs()                              */
    1248                 : /************************************************************************/
    1249                 : 
    1250               6 : const GDAL_GCP *GDALPamDataset::GetGCPs()
    1251                 : 
    1252                 : {
    1253               6 :     if( psPam && psPam->nGCPCount > 0 )
    1254               5 :         return psPam->pasGCPList;
    1255                 :     else
    1256               1 :         return GDALDataset::GetGCPs();
    1257                 : }
    1258                 : 
    1259                 : /************************************************************************/
    1260                 : /*                              SetGCPs()                               */
    1261                 : /************************************************************************/
    1262                 : 
    1263               1 : CPLErr GDALPamDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
    1264                 :                                 const char *pszGCPProjection )
    1265                 : 
    1266                 : {
    1267               1 :     PamInitialize();
    1268                 : 
    1269               1 :     if( psPam )
    1270                 :     {
    1271               1 :         CPLFree( psPam->pszGCPProjection );
    1272               1 :         if( psPam->nGCPCount > 0 )
    1273                 :         {
    1274               0 :             GDALDeinitGCPs( psPam->nGCPCount, psPam->pasGCPList );
    1275               0 :             CPLFree( psPam->pasGCPList );
    1276                 :         }
    1277                 : 
    1278               1 :         psPam->pszGCPProjection = CPLStrdup(pszGCPProjection);
    1279               1 :         psPam->nGCPCount = nGCPCount;
    1280               1 :         psPam->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
    1281                 : 
    1282               1 :         MarkPamDirty();
    1283                 : 
    1284               1 :         return CE_None;
    1285                 :     }
    1286                 :     else
    1287                 :     {
    1288               0 :         return GDALDataset::SetGCPs( nGCPCount, pasGCPList, pszGCPProjection );
    1289                 :     }
    1290                 : }
    1291                 : 
    1292                 : /************************************************************************/
    1293                 : /*                            SetMetadata()                             */
    1294                 : /************************************************************************/
    1295                 : 
    1296            1850 : CPLErr GDALPamDataset::SetMetadata( char **papszMetadata, 
    1297                 :                                     const char *pszDomain )
    1298                 : 
    1299                 : {
    1300            1850 :     PamInitialize();
    1301                 : 
    1302            1850 :     if( psPam )
    1303            1846 :         MarkPamDirty();
    1304                 : 
    1305            1850 :     return GDALDataset::SetMetadata( papszMetadata, pszDomain );
    1306                 : }
    1307                 : 
    1308                 : /************************************************************************/
    1309                 : /*                          SetMetadataItem()                           */
    1310                 : /************************************************************************/
    1311                 : 
    1312            7575 : CPLErr GDALPamDataset::SetMetadataItem( const char *pszName, 
    1313                 :                                         const char *pszValue, 
    1314                 :                                         const char *pszDomain )
    1315                 : 
    1316                 : {
    1317            7575 :     PamInitialize();
    1318                 : 
    1319            7575 :     if( psPam )
    1320            7573 :         MarkPamDirty();
    1321                 : 
    1322            7575 :     return GDALDataset::SetMetadataItem( pszName, pszValue, pszDomain );
    1323                 : }
    1324                 : 
    1325                 : /************************************************************************/
    1326                 : /*                          GetMetadataItem()                           */
    1327                 : /************************************************************************/
    1328                 : 
    1329            5539 : const char *GDALPamDataset::GetMetadataItem( const char *pszName, 
    1330                 :                                              const char *pszDomain )
    1331                 : 
    1332                 : {
    1333                 : /* -------------------------------------------------------------------- */
    1334                 : /*      A request against the ProxyOverviewRequest is a special         */
    1335                 : /*      mechanism to request an overview filename be allocated in       */
    1336                 : /*      the proxy pool location.  The allocated name is saved as        */
    1337                 : /*      metadata as well as being returned.                             */
    1338                 : /* -------------------------------------------------------------------- */
    1339            5539 :     if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
    1340                 :     {
    1341               3 :         CPLString osPrelimOvr = GetDescription();
    1342               3 :         osPrelimOvr += ":::OVR";
    1343                 :         
    1344               3 :         const char *pszProxyOvrFilename = PamAllocateProxy( osPrelimOvr );
    1345               3 :         if( pszProxyOvrFilename == NULL )
    1346               2 :             return NULL;
    1347                 :         
    1348               1 :         SetMetadataItem( "OVERVIEW_FILE", pszProxyOvrFilename, "OVERVIEWS" );
    1349                 :         
    1350               1 :         return pszProxyOvrFilename;
    1351                 :     }
    1352                 : 
    1353                 : /* -------------------------------------------------------------------- */
    1354                 : /*      If the OVERVIEW_FILE metadata is requested, we intercept the    */
    1355                 : /*      request in order to replace ":::BASE:::" with the path to       */
    1356                 : /*      the physical file - if available.  This is primarily for the    */
    1357                 : /*      purpose of managing subdataset overview filenames as being      */
    1358                 : /*      relative to the physical file the subdataset comes              */
    1359                 : /*      from. (#3287).                                                  */
    1360                 : /* -------------------------------------------------------------------- */
    1361            5536 :     else if( pszDomain != NULL 
    1362                 :              && EQUAL(pszDomain,"OVERVIEWS") 
    1363                 :              && EQUAL(pszName,"OVERVIEW_FILE") )
    1364                 :     {
    1365                 :         const char *pszOverviewFile = 
    1366            1627 :             GDALDataset::GetMetadataItem( pszName, pszDomain );
    1367                 : 
    1368            1627 :         if( pszOverviewFile == NULL 
    1369                 :             || !EQUALN(pszOverviewFile,":::BASE:::",10) )
    1370            1615 :             return pszOverviewFile;
    1371                 :         
    1372              12 :         CPLString osPath;
    1373                 : 
    1374              12 :         if( strlen(GetPhysicalFilename()) > 0 )
    1375              12 :             osPath = CPLGetPath(GetPhysicalFilename());
    1376                 :         else
    1377               0 :             osPath = CPLGetPath(GetDescription());
    1378                 : 
    1379              12 :         return CPLFormFilename( osPath, pszOverviewFile + 10, NULL );
    1380                 :     }
    1381                 : 
    1382                 : /* -------------------------------------------------------------------- */
    1383                 : /*      Everything else is a pass through.                              */
    1384                 : /* -------------------------------------------------------------------- */
    1385                 :     else
    1386            3909 :         return GDALDataset::GetMetadataItem( pszName, pszDomain );
    1387                 : 
    1388                 : }
    1389                 : 
    1390                 : /************************************************************************/
    1391                 : /*                            GetMetadata()                             */
    1392                 : /************************************************************************/
    1393                 : 
    1394             929 : char **GDALPamDataset::GetMetadata( const char *pszDomain )
    1395                 : 
    1396                 : {
    1397                 : //    if( pszDomain == NULL || !EQUAL(pszDomain,"ProxyOverviewRequest") )
    1398             929 :         return GDALDataset::GetMetadata( pszDomain );
    1399                 : }
    1400                 : 
    1401                 : /************************************************************************/
    1402                 : /*                             TryLoadAux()                             */
    1403                 : /************************************************************************/
    1404                 : 
    1405            7024 : CPLErr GDALPamDataset::TryLoadAux(char **papszSiblingFiles)
    1406                 : 
    1407                 : {
    1408                 : /* -------------------------------------------------------------------- */
    1409                 : /*      Initialize PAM.                                                 */
    1410                 : /* -------------------------------------------------------------------- */
    1411            7024 :     PamInitialize();
    1412            7024 :     if( psPam == NULL )
    1413               0 :         return CE_None;
    1414                 : 
    1415                 : /* -------------------------------------------------------------------- */
    1416                 : /*      What is the name of the physical file we are referencing?       */
    1417                 : /*      We allow an override via the psPam->pszPhysicalFile item.       */
    1418                 : /* -------------------------------------------------------------------- */
    1419            7024 :     const char *pszPhysicalFile = psPam->osPhysicalFilename;
    1420                 : 
    1421            7024 :     if( strlen(pszPhysicalFile) == 0 && GetDescription() != NULL )
    1422            6695 :         pszPhysicalFile = GetDescription();
    1423                 : 
    1424            7024 :     if( strlen(pszPhysicalFile) == 0 )
    1425               0 :         return CE_None;
    1426                 : 
    1427            7024 :     if( papszSiblingFiles )
    1428                 :     {
    1429            3679 :         CPLString osAuxFilename = CPLResetExtension( pszPhysicalFile, "aux");
    1430                 :         int iSibling = CSLFindString( papszSiblingFiles,
    1431            3679 :                                       CPLGetFilename(osAuxFilename) );
    1432            3679 :         if( iSibling < 0 )
    1433                 :         {
    1434            3673 :             osAuxFilename = pszPhysicalFile;
    1435            3673 :             osAuxFilename += ".aux";
    1436                 :             iSibling = CSLFindString( papszSiblingFiles,
    1437            3673 :                                       CPLGetFilename(osAuxFilename) );
    1438            3673 :             if( iSibling < 0 )
    1439            3673 :                 return CE_None;
    1440               0 :         }
    1441                 :     }
    1442                 : 
    1443                 : /* -------------------------------------------------------------------- */
    1444                 : /*      Try to open .aux file.                                          */
    1445                 : /* -------------------------------------------------------------------- */
    1446                 :     GDALDataset *poAuxDS = GDALFindAssociatedAuxFile( pszPhysicalFile,
    1447            3351 :                                                       GA_ReadOnly, this );
    1448                 : 
    1449            3351 :     if( poAuxDS == NULL )
    1450            3343 :         return CE_None;
    1451                 : 
    1452               8 :     psPam->osAuxFilename = poAuxDS->GetDescription();
    1453                 : 
    1454                 : /* -------------------------------------------------------------------- */
    1455                 : /*      Do we have an SRS on the aux file?                              */
    1456                 : /* -------------------------------------------------------------------- */
    1457               8 :     if( strlen(poAuxDS->GetProjectionRef()) > 0 )
    1458               0 :         GDALPamDataset::SetProjection( poAuxDS->GetProjectionRef() );
    1459                 : 
    1460                 : /* -------------------------------------------------------------------- */
    1461                 : /*      Geotransform.                                                   */
    1462                 : /* -------------------------------------------------------------------- */
    1463               8 :     if( poAuxDS->GetGeoTransform( psPam->adfGeoTransform ) == CE_None )
    1464               0 :         psPam->bHaveGeoTransform = TRUE;
    1465                 : 
    1466                 : /* -------------------------------------------------------------------- */
    1467                 : /*      GCPs                                                            */
    1468                 : /* -------------------------------------------------------------------- */
    1469               8 :     if( poAuxDS->GetGCPCount() > 0 )
    1470                 :     {
    1471               0 :         psPam->nGCPCount = poAuxDS->GetGCPCount();
    1472                 :         psPam->pasGCPList = GDALDuplicateGCPs( psPam->nGCPCount, 
    1473               0 :                                                poAuxDS->GetGCPs() );
    1474                 :     }
    1475                 : 
    1476                 : /* -------------------------------------------------------------------- */
    1477                 : /*      Apply metadata. We likely ought to be merging this in rather    */
    1478                 : /*      than overwriting everything that was there.                     */
    1479                 : /* -------------------------------------------------------------------- */
    1480               8 :     char **papszMD = poAuxDS->GetMetadata();
    1481               8 :     if( CSLCount(papszMD) > 0 )
    1482                 :     {
    1483                 :         char **papszMerged = 
    1484               0 :             CSLMerge( CSLDuplicate(GetMetadata()), papszMD );
    1485               0 :         GDALPamDataset::SetMetadata( papszMerged );
    1486               0 :         CSLDestroy( papszMerged );
    1487                 :     }
    1488                 : 
    1489               8 :     papszMD = poAuxDS->GetMetadata("XFORMS");
    1490               8 :     if( CSLCount(papszMD) > 0 )
    1491                 :     {
    1492                 :         char **papszMerged = 
    1493               0 :             CSLMerge( CSLDuplicate(GetMetadata("XFORMS")), papszMD );
    1494               0 :         GDALPamDataset::SetMetadata( papszMerged, "XFORMS" );
    1495               0 :         CSLDestroy( papszMerged );
    1496                 :     }
    1497                 : 
    1498                 : /* ==================================================================== */
    1499                 : /*      Process bands.                                                  */
    1500                 : /* ==================================================================== */
    1501                 :     int iBand;
    1502                 : 
    1503              16 :     for( iBand = 0; iBand < poAuxDS->GetRasterCount(); iBand++ )
    1504                 :     {
    1505               8 :         if( iBand >= GetRasterCount() )
    1506               0 :             break;
    1507                 : 
    1508               8 :         GDALRasterBand *poAuxBand = poAuxDS->GetRasterBand( iBand+1 );
    1509               8 :         GDALRasterBand *poBand = GetRasterBand( iBand+1 );
    1510                 : 
    1511               8 :         papszMD = poAuxBand->GetMetadata();
    1512               8 :         if( CSLCount(papszMD) > 0 )
    1513                 :         {
    1514                 :             char **papszMerged = 
    1515               8 :                 CSLMerge( CSLDuplicate(poBand->GetMetadata()), papszMD );
    1516               8 :             poBand->SetMetadata( papszMerged );
    1517               8 :             CSLDestroy( papszMerged );
    1518                 :         }
    1519                 : 
    1520               8 :         if( strlen(poAuxBand->GetDescription()) > 0 )
    1521               8 :             poBand->SetDescription( poAuxBand->GetDescription() );
    1522                 : 
    1523               8 :         if( poAuxBand->GetCategoryNames() != NULL )
    1524               0 :             poBand->SetCategoryNames( poAuxBand->GetCategoryNames() );
    1525                 : 
    1526               8 :         if( poAuxBand->GetColorTable() != NULL 
    1527               0 :             && poBand->GetColorTable() == NULL )
    1528               0 :             poBand->SetColorTable( poAuxBand->GetColorTable() );
    1529                 : 
    1530                 :         // histograms?
    1531                 :         double dfMin, dfMax;
    1532               8 :         int nBuckets, *panHistogram=NULL;
    1533                 : 
    1534               8 :         if( poAuxBand->GetDefaultHistogram( &dfMin, &dfMax, 
    1535                 :                                             &nBuckets, &panHistogram,
    1536               8 :                                             FALSE, NULL, NULL ) == CE_None )
    1537                 :         {
    1538                 :             poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, 
    1539               1 :                                          panHistogram );
    1540               1 :             CPLFree( panHistogram );
    1541                 :         }
    1542                 : 
    1543                 :         // RAT 
    1544               8 :         if( poAuxBand->GetDefaultRAT() != NULL )
    1545               1 :             poBand->SetDefaultRAT( poAuxBand->GetDefaultRAT() );
    1546                 : 
    1547                 :         // NoData
    1548               8 :         int bSuccess = FALSE;
    1549               8 :         double dfNoDataValue = poAuxBand->GetNoDataValue( &bSuccess );
    1550               8 :         if( bSuccess )
    1551               3 :             poBand->SetNoDataValue( dfNoDataValue );
    1552                 :     }
    1553                 : 
    1554               8 :     GDALClose( poAuxDS );
    1555                 :     
    1556                 : /* -------------------------------------------------------------------- */
    1557                 : /*      Mark PAM info as clean.                                         */
    1558                 : /* -------------------------------------------------------------------- */
    1559               8 :     nPamFlags &= ~GPF_DIRTY;
    1560                 : 
    1561               8 :     return CE_Failure;
    1562                 : }

Generated by: LCOV version 1.7