LCOV - code coverage report
Current view: directory - gcore - gdalpamdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 460 345 75.0 %
Date: 2010-01-09 Functions: 31 28 90.3 %

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

Generated by: LCOV version 1.7