LTP GCOV extension - code coverage report
Current view: directory - gcore - gdalpamdataset.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 453
Code covered: 81.2 % Executed lines: 368

       1                 : /******************************************************************************
       2                 :  * $Id: gdalpamdataset.cpp 19926 2010-06-27 13:15:59Z 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 19926 2010-06-27 13:15:59Z 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 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            7897 : GDALPamDataset::GDALPamDataset()
     125                 : 
     126                 : {
     127            7897 :     nPamFlags = 0;
     128            7897 :     psPam = NULL;
     129            7897 :     SetMOFlags( GetMOFlags() | GMO_PAM_CLASS );
     130            7897 : }
     131                 : 
     132                 : /************************************************************************/
     133                 : /*                          ~GDALPamDataset()                           */
     134                 : /************************************************************************/
     135                 : 
     136            7897 : GDALPamDataset::~GDALPamDataset()
     137                 : 
     138                 : {
     139            7897 :     if( nPamFlags & GPF_DIRTY )
     140                 :     {
     141             349 :         CPLDebug( "GDALPamDataset", "In destructor with dirty metadata." );
     142             349 :         FlushCache();
     143                 :     }
     144                 : 
     145            7897 :     PamClear();
     146            7897 : }
     147                 : 
     148                 : /************************************************************************/
     149                 : /*                             FlushCache()                             */
     150                 : /************************************************************************/
     151                 : 
     152           12294 : void GDALPamDataset::FlushCache()
     153                 : 
     154                 : {
     155           12294 :     GDALDataset::FlushCache();
     156           12294 :     if( nPamFlags & GPF_DIRTY )
     157             889 :         TrySaveXML();
     158           12294 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                           SerializeToXML()                           */
     162                 : /************************************************************************/
     163                 : 
     164             618 : CPLXMLNode *GDALPamDataset::SerializeToXML( const char *pszUnused )
     165                 : 
     166                 : {
     167             618 :     CPLString oFmt;
     168                 : 
     169             618 :     if( psPam == NULL )
     170               0 :         return NULL;
     171                 : 
     172                 : /* -------------------------------------------------------------------- */
     173                 : /*      Setup root node and attributes.                                 */
     174                 : /* -------------------------------------------------------------------- */
     175                 :     CPLXMLNode *psDSTree;
     176                 : 
     177             618 :     psDSTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMDataset" );
     178                 : 
     179                 : /* -------------------------------------------------------------------- */
     180                 : /*      SRS                                                             */
     181                 : /* -------------------------------------------------------------------- */
     182             618 :     if( psPam->pszProjection != NULL && strlen(psPam->pszProjection) > 0 )
     183             220 :         CPLSetXMLValue( psDSTree, "SRS", psPam->pszProjection );
     184                 : 
     185                 : /* -------------------------------------------------------------------- */
     186                 : /*      GeoTransform.                                                   */
     187                 : /* -------------------------------------------------------------------- */
     188             618 :     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             174 :                                      psPam->adfGeoTransform[5] ) );
     198                 :     }
     199                 : 
     200                 : /* -------------------------------------------------------------------- */
     201                 : /*      Metadata.                                                       */
     202                 : /* -------------------------------------------------------------------- */
     203                 :     CPLXMLNode *psMD;
     204                 : 
     205             618 :     psMD = oMDMD.Serialize();
     206             618 :     if( psMD != NULL )
     207                 :     {
     208             493 :         if( psMD->psChild == NULL && psMD->psNext == NULL )
     209              18 :             CPLDestroyXMLNode( psMD );
     210                 :         else
     211             457 :             CPLAddXMLChild( psDSTree, psMD );
     212                 :     }
     213                 : 
     214                 : /* -------------------------------------------------------------------- */
     215                 : /*      GCPs                                                            */
     216                 : /* -------------------------------------------------------------------- */
     217             618 :     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            1611 :     for( iBand = 0; iBand < GetRasterCount(); iBand++ )
     263                 :     {
     264                 :         CPLXMLNode *psBandTree;
     265                 : 
     266                 :         GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     267             993 :             GetRasterBand(iBand+1);
     268                 : 
     269             993 :         if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     270              15 :             continue;
     271                 : 
     272             978 :         psBandTree = poBand->SerializeToXML( pszUnused );
     273                 : 
     274             978 :         if( psBandTree != NULL )
     275             473 :             CPLAddXMLChild( psDSTree, psBandTree );
     276                 :     }
     277                 : 
     278                 : /* -------------------------------------------------------------------- */
     279                 : /*      We don't want to return anything if we had no metadata to       */
     280                 : /*      attach.                                                         */
     281                 : /* -------------------------------------------------------------------- */
     282             618 :     if( psDSTree->psChild == NULL )
     283                 :     {
     284               6 :         CPLDestroyXMLNode( psDSTree );
     285               6 :         psDSTree = NULL;
     286                 :     }
     287                 : 
     288             618 :     return psDSTree;
     289                 : }
     290                 : 
     291                 : /************************************************************************/
     292                 : /*                           PamInitialize()                            */
     293                 : /************************************************************************/
     294                 : 
     295          497277 : 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          497277 :     if( psPam || (nPamFlags & GPF_DISABLED) )
     305          490971 :         return;
     306                 : 
     307            6306 :     if( !CSLTestBoolean( CPLGetConfigOption( "GDAL_PAM_ENABLED", 
     308                 :                                              pszPamDefault ) ) )
     309                 :     {
     310               0 :         nPamFlags |= GPF_DISABLED;
     311               0 :         return;
     312                 :     }
     313                 : 
     314            6306 :     if( EQUAL( CPLGetConfigOption( "GDAL_PAM_MODE", "PAM" ), "AUX") )
     315               0 :         nPamFlags |= GPF_AUXMODE;
     316                 : 
     317            6306 :     psPam = new GDALDatasetPamInfo;
     318            6306 :     psPam->pszPamFilename = NULL;
     319            6306 :     psPam->pszProjection = NULL;
     320            6306 :     psPam->bHaveGeoTransform = FALSE;
     321            6306 :     psPam->nGCPCount = 0;
     322            6306 :     psPam->pasGCPList = NULL;
     323            6306 :     psPam->pszGCPProjection = NULL;
     324                 : 
     325                 :     int iBand;
     326                 :     
     327          485474 :     for( iBand = 0; iBand < GetRasterCount(); iBand++ )
     328                 :     {
     329                 :         GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     330          479168 :             GetRasterBand(iBand+1);
     331                 :         
     332          479168 :         if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     333              74 :             continue;
     334                 : 
     335          479094 :         poBand->PamInitialize();
     336                 :     }
     337                 : }
     338                 : 
     339                 : /************************************************************************/
     340                 : /*                              PamClear()                              */
     341                 : /************************************************************************/
     342                 : 
     343            7897 : void GDALPamDataset::PamClear()
     344                 : 
     345                 : {
     346            7897 :     if( psPam )
     347                 :     {
     348            6306 :         CPLFree( psPam->pszPamFilename );
     349            6306 :         CPLFree( psPam->pszProjection );
     350            6306 :         CPLFree( psPam->pszGCPProjection );
     351            6306 :         if( psPam->nGCPCount > 0 )
     352                 :         {
     353               2 :             GDALDeinitGCPs( psPam->nGCPCount, psPam->pasGCPList );
     354               2 :             CPLFree( psPam->pasGCPList );
     355                 :         }
     356                 : 
     357            6306 :         delete psPam;
     358            6306 :         psPam = NULL;
     359                 :     }
     360            7897 : }
     361                 : 
     362                 : /************************************************************************/
     363                 : /*                              XMLInit()                               */
     364                 : /************************************************************************/
     365                 : 
     366             428 : CPLErr GDALPamDataset::XMLInit( CPLXMLNode *psTree, const char *pszUnused )
     367                 : 
     368                 : {
     369                 : /* -------------------------------------------------------------------- */
     370                 : /*      Check for an SRS node.                                          */
     371                 : /* -------------------------------------------------------------------- */
     372             428 :     if( strlen(CPLGetXMLValue(psTree, "SRS", "")) > 0 )
     373                 :     {
     374             136 :         OGRSpatialReference oSRS;
     375                 : 
     376             136 :         CPLFree( psPam->pszProjection );
     377             136 :         psPam->pszProjection = NULL;
     378                 : 
     379             136 :         if( oSRS.SetFromUserInput( CPLGetXMLValue(psTree, "SRS", "") )
     380                 :             == OGRERR_NONE )
     381             136 :             oSRS.exportToWkt( &(psPam->pszProjection) );
     382                 :     }
     383                 : 
     384                 : /* -------------------------------------------------------------------- */
     385                 : /*      Check for a GeoTransform node.                                  */
     386                 : /* -------------------------------------------------------------------- */
     387             428 :     if( strlen(CPLGetXMLValue(psTree, "GeoTransform", "")) > 0 )
     388                 :     {
     389             138 :         const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
     390                 :         char  **papszTokens;
     391                 : 
     392             138 :         papszTokens = CSLTokenizeStringComplex( pszGT, ",", FALSE, FALSE );
     393             138 :         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             966 :             for( int iTA = 0; iTA < 6; iTA++ )
     401             828 :                 psPam->adfGeoTransform[iTA] = atof(papszTokens[iTA]);
     402             138 :             psPam->bHaveGeoTransform = TRUE;
     403                 :         }
     404                 : 
     405             138 :         CSLDestroy( papszTokens );
     406                 :     }
     407                 : 
     408                 : /* -------------------------------------------------------------------- */
     409                 : /*      Check for GCPs.                                                 */
     410                 : /* -------------------------------------------------------------------- */
     411             428 :     CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
     412                 : 
     413             428 :     if( psGCPList != NULL )
     414                 :     {
     415                 :         CPLXMLNode *psXMLGCP;
     416               2 :         OGRSpatialReference oSRS;
     417               2 :         const char *pszRawProj = CPLGetXMLValue(psGCPList, "Projection", "");
     418                 : 
     419               2 :         CPLFree( psPam->pszGCPProjection );
     420                 : 
     421               2 :         if( strlen(pszRawProj) > 0 
     422                 :             && oSRS.SetFromUserInput( pszRawProj ) == OGRERR_NONE )
     423               2 :             oSRS.exportToWkt( &(psPam->pszGCPProjection) );
     424                 :         else
     425               0 :             psPam->pszGCPProjection = CPLStrdup("");
     426                 : 
     427                 :         // Count GCPs.
     428               2 :         int  nGCPMax = 0;
     429                 :          
     430              12 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     431                 :              psXMLGCP = psXMLGCP->psNext )
     432              10 :             nGCPMax++;
     433                 :          
     434               2 :         psPam->pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax);
     435                 :          
     436              12 :         for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL; 
     437                 :              psXMLGCP = psXMLGCP->psNext )
     438                 :         {
     439              10 :             GDAL_GCP *psGCP = psPam->pasGCPList + psPam->nGCPCount;
     440                 : 
     441              10 :             if( !EQUAL(psXMLGCP->pszValue,"GCP") || 
     442                 :                 psXMLGCP->eType != CXT_Element )
     443               2 :                 continue;
     444                 :              
     445               8 :             GDALInitGCPs( 1, psGCP );
     446                 :              
     447               8 :             CPLFree( psGCP->pszId );
     448               8 :             psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
     449                 :              
     450               8 :             CPLFree( psGCP->pszInfo );
     451               8 :             psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
     452                 :              
     453               8 :             psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
     454               8 :             psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
     455                 :              
     456               8 :             psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
     457               8 :             psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
     458               8 :             psGCP->dfGCPZ = atof(CPLGetXMLValue(psXMLGCP,"Z","0.0"));
     459                 : 
     460               8 :             psPam->nGCPCount++;
     461               2 :         }
     462                 :     }
     463                 : 
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*      Apply any dataset level metadata.                               */
     466                 : /* -------------------------------------------------------------------- */
     467             428 :     oMDMD.XMLInit( psTree, TRUE );
     468                 : 
     469                 : /* -------------------------------------------------------------------- */
     470                 : /*      Process bands.                                                  */
     471                 : /* -------------------------------------------------------------------- */
     472                 :     CPLXMLNode *psBandTree;
     473                 : 
     474            1311 :     for( psBandTree = psTree->psChild; 
     475                 :          psBandTree != NULL; psBandTree = psBandTree->psNext )
     476                 :     {
     477             883 :         if( psBandTree->eType != CXT_Element
     478                 :             || !EQUAL(psBandTree->pszValue,"PAMRasterBand") )
     479             562 :             continue;
     480                 : 
     481             321 :         int nBand = atoi(CPLGetXMLValue( psBandTree, "band", "0"));
     482                 : 
     483             321 :         if( nBand < 1 || nBand > GetRasterCount() )
     484               0 :             continue;
     485                 : 
     486                 :         GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     487             321 :             GetRasterBand(nBand);
     488                 : 
     489             321 :         if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     490               0 :             continue;
     491                 : 
     492             321 :         poBand->XMLInit( psBandTree, pszUnused );
     493                 :     }
     494                 : 
     495                 : /* -------------------------------------------------------------------- */
     496                 : /*      Clear dirty flag.                                               */
     497                 : /* -------------------------------------------------------------------- */
     498             428 :     nPamFlags &= ~GPF_DIRTY;
     499                 : 
     500             428 :     return CE_None;
     501                 : }
     502                 : 
     503                 : /************************************************************************/
     504                 : /*                        SetPhysicalFilename()                         */
     505                 : /************************************************************************/
     506                 : 
     507             322 : void GDALPamDataset::SetPhysicalFilename( const char *pszFilename )
     508                 : 
     509                 : {
     510             322 :     PamInitialize();
     511                 : 
     512             322 :     if( psPam )
     513             322 :         psPam->osPhysicalFilename = pszFilename;
     514             322 : }
     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             322 : void GDALPamDataset::SetSubdatasetName( const char *pszSubdataset )
     536                 : 
     537                 : {
     538             322 :     PamInitialize();
     539                 : 
     540             322 :     if( psPam )
     541             322 :         psPam->osSubdatasetName = pszSubdataset;
     542             322 : }
     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            6526 : const char *GDALPamDataset::BuildPamFilename()
     564                 : 
     565                 : {
     566            6526 :     if( psPam == NULL )
     567               0 :         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            6526 :     if( psPam->pszPamFilename != NULL )
     574             500 :         return psPam->pszPamFilename;
     575                 : 
     576            6026 :     const char *pszPhysicalFile = psPam->osPhysicalFilename;
     577                 : 
     578            6026 :     if( strlen(pszPhysicalFile) == 0 && GetDescription() != NULL )
     579            5708 :         pszPhysicalFile = GetDescription();
     580                 : 
     581            6026 :     if( strlen(pszPhysicalFile) == 0 )
     582               3 :         return NULL;
     583                 : 
     584                 : /* -------------------------------------------------------------------- */
     585                 : /*      Try a proxy lookup, otherwise just add .aux.xml.                */
     586                 : /* -------------------------------------------------------------------- */
     587            6023 :     const char *pszProxyPam = PamGetProxy( pszPhysicalFile );
     588            6023 :     if( pszProxyPam != NULL )
     589               0 :         psPam->pszPamFilename = CPLStrdup(pszProxyPam);
     590                 :     else
     591                 :     {
     592            6023 :         psPam->pszPamFilename = (char*) CPLMalloc(strlen(pszPhysicalFile)+10);
     593            6023 :         strcpy( psPam->pszPamFilename, pszPhysicalFile );
     594            6023 :         strcat( psPam->pszPamFilename, ".aux.xml" );
     595                 :     }
     596                 : 
     597            6023 :     return psPam->pszPamFilename;
     598                 : }
     599                 : 
     600                 : /************************************************************************/
     601                 : /*                             TryLoadXML()                             */
     602                 : /************************************************************************/
     603                 : 
     604            5905 : CPLErr GDALPamDataset::TryLoadXML()
     605                 : 
     606                 : {
     607            5905 :     CPLXMLNode *psTree = NULL;
     608                 : 
     609            5905 :     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            5905 :     nPamFlags &= ~GPF_DIRTY;
     620                 : 
     621                 : /* -------------------------------------------------------------------- */
     622                 : /*      Try reading the file.                                           */
     623                 : /* -------------------------------------------------------------------- */
     624            5905 :     if( !BuildPamFilename() )
     625               0 :         return CE_None;
     626                 : 
     627                 :     VSIStatBufL sStatBuf;
     628                 : 
     629            5905 :     if( VSIStatL( psPam->pszPamFilename, &sStatBuf ) == 0 
     630                 :         && VSI_ISREG( sStatBuf.st_mode ) )
     631                 :     {
     632             501 :         CPLErrorReset();
     633             501 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     634             501 :         psTree = CPLParseXMLFile( psPam->pszPamFilename );
     635             501 :         CPLPopErrorHandler();
     636                 :     }
     637                 : 
     638                 : /* -------------------------------------------------------------------- */
     639                 : /*      If we are looking for a subdataset, search for it's subtree     */
     640                 : /*      now.                                                            */
     641                 : /* -------------------------------------------------------------------- */
     642            5905 :     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            5905 :     if( psTree == NULL )
     673            5477 :         return TryLoadAux();
     674                 : 
     675                 : /* -------------------------------------------------------------------- */
     676                 : /*      Initialize ourselves from this XML tree.                        */
     677                 : /* -------------------------------------------------------------------- */
     678                 :     CPLErr eErr;
     679                 : 
     680             428 :     CPLString osVRTPath(CPLGetPath(psPam->pszPamFilename));
     681             428 :     eErr = XMLInit( psTree, osVRTPath );
     682                 : 
     683             428 :     CPLDestroyXMLNode( psTree );
     684                 : 
     685             428 :     if( eErr != CE_None )
     686               0 :         PamClear();
     687                 : 
     688             428 :     return eErr;
     689                 : }
     690                 : 
     691                 : /************************************************************************/
     692                 : /*                             TrySaveXML()                             */
     693                 : /************************************************************************/
     694                 : 
     695             889 : CPLErr GDALPamDataset::TrySaveXML()
     696                 : 
     697                 : {
     698                 :     CPLXMLNode *psTree;
     699             889 :     CPLErr eErr = CE_None;
     700                 : 
     701             889 :     nPamFlags &= ~GPF_DIRTY;
     702                 : 
     703             889 :     if( psPam == NULL || (nPamFlags & GPF_NOSAVE) )
     704             268 :         return CE_None;
     705                 : 
     706                 : /* -------------------------------------------------------------------- */
     707                 : /*      Make sure we know the filename we want to store in.             */
     708                 : /* -------------------------------------------------------------------- */
     709             621 :     if( !BuildPamFilename() )
     710               3 :         return CE_None;
     711                 : 
     712                 : /* -------------------------------------------------------------------- */
     713                 : /*      Build the XML representation of the auxilary metadata.          */
     714                 : /* -------------------------------------------------------------------- */
     715             618 :     psTree = SerializeToXML( NULL );
     716                 : 
     717             618 :     if( psTree == NULL )
     718                 :     {
     719                 :         /* If we have unset all metadata, we have to delete the PAM file */
     720               6 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     721               6 :         VSIUnlink(psPam->pszPamFilename);
     722               6 :         CPLPopErrorHandler();
     723               6 :         return CE_None;
     724                 :     }
     725                 : 
     726                 : /* -------------------------------------------------------------------- */
     727                 : /*      If we are working with a subdataset, we need to integrate       */
     728                 : /*      the subdataset tree within the whole existing pam tree,         */
     729                 : /*      after removing any old version of the same subdataset.          */
     730                 : /* -------------------------------------------------------------------- */
     731             612 :     if( psPam->osSubdatasetName.size() != 0 )
     732                 :     {
     733                 :         CPLXMLNode *psOldTree, *psSubTree;
     734                 : 
     735               4 :         CPLErrorReset();
     736               4 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     737               4 :         psOldTree = CPLParseXMLFile( psPam->pszPamFilename );
     738               4 :         CPLPopErrorHandler();
     739                 : 
     740               4 :         if( psOldTree == NULL )
     741               4 :             psOldTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMDataset" );
     742                 : 
     743               4 :         for( psSubTree = psOldTree->psChild; 
     744                 :              psSubTree != NULL;
     745                 :              psSubTree = psSubTree->psNext )
     746                 :         {
     747               0 :             if( psSubTree->eType != CXT_Element
     748                 :                 || !EQUAL(psSubTree->pszValue,"Subdataset") )
     749               0 :                 continue;
     750                 : 
     751               0 :             if( !EQUAL(CPLGetXMLValue( psSubTree, "name", "" ),
     752                 :                        psPam->osSubdatasetName) )
     753               0 :                 continue;
     754                 : 
     755               0 :             break;
     756                 :         }
     757                 : 
     758               4 :         if( psSubTree == NULL )
     759                 :         {
     760                 :             psSubTree = CPLCreateXMLNode( psOldTree, CXT_Element, 
     761               4 :                                           "Subdataset" );
     762                 :             CPLCreateXMLNode( 
     763                 :                 CPLCreateXMLNode( psSubTree, CXT_Attribute, "name" ),
     764               4 :                 CXT_Text, psPam->osSubdatasetName );
     765                 :         }
     766                 :         
     767               4 :         CPLXMLNode *psOldPamDataset = CPLGetXMLNode( psSubTree, "PAMDataset");
     768               4 :         if( psOldPamDataset != NULL )
     769                 :         {
     770               0 :             CPLRemoveXMLChild( psSubTree, psOldPamDataset );
     771               0 :             CPLDestroyXMLNode( psOldPamDataset );
     772                 :         }
     773                 : 
     774               4 :         CPLAddXMLChild( psSubTree, psTree );
     775               4 :         psTree = psOldTree;
     776                 :     }
     777                 : 
     778                 : /* -------------------------------------------------------------------- */
     779                 : /*      Try saving the auxilary metadata.                               */
     780                 : /* -------------------------------------------------------------------- */
     781                 :     int bSaved;
     782                 :     
     783             612 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     784             612 :     bSaved = CPLSerializeXMLTreeToFile( psTree, psPam->pszPamFilename );
     785             612 :     CPLPopErrorHandler();
     786                 : 
     787                 : /* -------------------------------------------------------------------- */
     788                 : /*      If it fails, check if we have a proxy directory for auxilary    */
     789                 : /*      metadata to be stored in, and try to save there.                */
     790                 : /* -------------------------------------------------------------------- */
     791             612 :     if( bSaved )
     792             612 :         eErr = CE_None;
     793                 :     else
     794                 :     {
     795                 :         const char *pszNewPam;
     796               0 :         const char *pszBasename = GetDescription();
     797                 : 
     798               0 :         if( psPam && psPam->osPhysicalFilename.length() > 0 )
     799               0 :             pszBasename = psPam->osPhysicalFilename;
     800                 :             
     801               0 :         if( PamGetProxy(pszBasename) == NULL 
     802                 :             && ((pszNewPam = PamAllocateProxy(pszBasename)) != NULL))
     803                 :         {
     804               0 :             CPLErrorReset();
     805               0 :             CPLFree( psPam->pszPamFilename );
     806               0 :             psPam->pszPamFilename = CPLStrdup(pszNewPam);
     807               0 :             eErr = TrySaveXML();
     808                 :         }
     809                 :         else
     810                 :         {
     811                 :             CPLError( CE_Warning, CPLE_AppDefined, 
     812                 :                       "Unable to save auxilary information in %s.",
     813               0 :                       psPam->pszPamFilename );
     814               0 :             eErr = CE_Warning;
     815                 :         }
     816                 :     }
     817                 :     
     818                 : /* -------------------------------------------------------------------- */
     819                 : /*      Cleanup                                                         */
     820                 : /* -------------------------------------------------------------------- */
     821             612 :     CPLDestroyXMLNode( psTree );
     822                 : 
     823             612 :     return eErr;
     824                 : }
     825                 : 
     826                 : /************************************************************************/
     827                 : /*                             CloneInfo()                              */
     828                 : /************************************************************************/
     829                 : 
     830             377 : CPLErr GDALPamDataset::CloneInfo( GDALDataset *poSrcDS, int nCloneFlags )
     831                 : 
     832                 : {
     833             377 :     int bOnlyIfMissing = nCloneFlags & GCIF_ONLY_IF_MISSING;
     834             377 :     int nSavedMOFlags = GetMOFlags();
     835                 : 
     836             377 :     PamInitialize();
     837                 : 
     838                 : /* -------------------------------------------------------------------- */
     839                 : /*      Supress NotImplemented error messages - mainly needed if PAM    */
     840                 : /*      disabled.                                                       */
     841                 : /* -------------------------------------------------------------------- */
     842             377 :     SetMOFlags( nSavedMOFlags | GMO_IGNORE_UNIMPLEMENTED );
     843                 : 
     844                 : /* -------------------------------------------------------------------- */
     845                 : /*      GeoTransform                                                    */
     846                 : /* -------------------------------------------------------------------- */
     847             377 :     if( nCloneFlags & GCIF_GEOTRANSFORM )
     848                 :     {
     849                 :         double adfGeoTransform[6];
     850                 : 
     851             377 :         if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
     852                 :         {
     853                 :             double adfOldGT[6];
     854                 : 
     855             318 :             if( !bOnlyIfMissing || GetGeoTransform( adfOldGT ) != CE_None )
     856              57 :                 SetGeoTransform( adfGeoTransform );
     857                 :         }
     858                 :     }
     859                 : 
     860                 : /* -------------------------------------------------------------------- */
     861                 : /*      Projection                                                      */
     862                 : /* -------------------------------------------------------------------- */
     863             377 :     if( nCloneFlags & GCIF_PROJECTION )
     864                 :     {
     865             377 :         const char *pszWKT = poSrcDS->GetProjectionRef();
     866                 : 
     867             377 :         if( pszWKT != NULL && strlen(pszWKT) > 0 )
     868                 :         {
     869             311 :             if( !bOnlyIfMissing 
     870                 :                 || GetProjectionRef() == NULL
     871                 :                 || strlen(GetProjectionRef()) == 0 )
     872              70 :                 SetProjection( pszWKT );
     873                 :         }
     874                 :     }
     875                 : 
     876                 : /* -------------------------------------------------------------------- */
     877                 : /*      GCPs                                                            */
     878                 : /* -------------------------------------------------------------------- */
     879             377 :     if( nCloneFlags & GCIF_GCPS )
     880                 :     {
     881             377 :         if( poSrcDS->GetGCPCount() > 0 )
     882                 :         {
     883               3 :             if( !bOnlyIfMissing || GetGCPCount() == 0 )
     884                 :             {
     885                 :                 SetGCPs( poSrcDS->GetGCPCount(), 
     886                 :                          poSrcDS->GetGCPs(), 
     887               0 :                          poSrcDS->GetGCPProjection() );
     888                 :             }
     889                 :         }
     890                 :     }
     891                 : 
     892                 : /* -------------------------------------------------------------------- */
     893                 : /*      Metadata                                                        */
     894                 : /* -------------------------------------------------------------------- */
     895             377 :     if( nCloneFlags & GCIF_METADATA )
     896                 :     {
     897             377 :         if( poSrcDS->GetMetadata() != NULL )
     898                 :         {
     899             308 :             if( !bOnlyIfMissing 
     900                 :                 || CSLCount(GetMetadata()) != CSLCount(poSrcDS->GetMetadata()) )
     901                 :             {
     902             158 :                 SetMetadata( poSrcDS->GetMetadata() );
     903                 :             }
     904                 :         }
     905             377 :         if( poSrcDS->GetMetadata("RPC") != NULL )
     906                 :         {
     907               2 :             if( !bOnlyIfMissing 
     908                 :                 || CSLCount(GetMetadata("RPC")) 
     909                 :                    != CSLCount(poSrcDS->GetMetadata("RPC")) )
     910                 :             {
     911               0 :                 SetMetadata( poSrcDS->GetMetadata("RPC"), "RPC" );
     912                 :             }
     913                 :         }
     914                 :     }
     915                 : 
     916                 : /* -------------------------------------------------------------------- */
     917                 : /*      Process bands.                                                  */
     918                 : /* -------------------------------------------------------------------- */
     919             377 :     if( nCloneFlags & GCIF_PROCESS_BANDS )
     920                 :     {
     921                 :         int iBand;
     922                 : 
     923             947 :         for( iBand = 0; iBand < GetRasterCount(); iBand++ )
     924                 :         {
     925                 :             GDALPamRasterBand *poBand = (GDALPamRasterBand *)
     926             570 :                 GetRasterBand(iBand+1);
     927                 : 
     928             570 :             if( poBand == NULL || !(poBand->GetMOFlags() & GMO_PAM_CLASS) )
     929               5 :                 continue;
     930                 : 
     931             565 :             if( poSrcDS->GetRasterCount() >= iBand+1 )
     932                 :                 poBand->CloneInfo( poSrcDS->GetRasterBand(iBand+1), 
     933             565 :                                    nCloneFlags );
     934                 :             else
     935               0 :                 CPLDebug( "GDALPamDataset", "Skipping CloneInfo for band not in source, this is a bit unusual!" );
     936                 :         }
     937                 :     }
     938                 : 
     939                 : /* -------------------------------------------------------------------- */
     940                 : /*      Copy masks.  These are really copied at a lower level using     */
     941                 : /*      GDALDefaultOverviews, for formats with no native mask           */
     942                 : /*      support but this is a convenient central point to put this      */
     943                 : /*      for most drivers.                                               */
     944                 : /* -------------------------------------------------------------------- */
     945             377 :     if( nCloneFlags & GCIF_MASK )
     946                 :     {
     947             375 :         GDALDriver::DefaultCopyMasks( poSrcDS, this, FALSE );
     948                 :     }
     949                 : 
     950                 : /* -------------------------------------------------------------------- */
     951                 : /*      Restore MO flags.                                               */
     952                 : /* -------------------------------------------------------------------- */
     953             377 :     SetMOFlags( nSavedMOFlags );
     954                 : 
     955             377 :     return CE_None;
     956                 : }
     957                 : 
     958                 : /************************************************************************/
     959                 : /*                            GetFileList()                             */
     960                 : /*                                                                      */
     961                 : /*      Add .aux.xml or .aux file into file list as appropriate.        */
     962                 : /************************************************************************/
     963                 : 
     964            1320 : char **GDALPamDataset::GetFileList()
     965                 : 
     966                 : {
     967                 :     VSIStatBufL sStatBuf;
     968            1320 :     char **papszFileList = GDALDataset::GetFileList();
     969                 : 
     970            1320 :     if( psPam && psPam->osPhysicalFilename.size() > 0 
     971                 :         && CSLFindString( papszFileList, psPam->osPhysicalFilename ) == -1 )
     972                 :     {
     973                 :         papszFileList = CSLInsertString( papszFileList, 0, 
     974             104 :                                          psPam->osPhysicalFilename );
     975                 :     }
     976                 : 
     977            1320 :     if( psPam && psPam->pszPamFilename 
     978                 :         && (nPamFlags & GPF_DIRTY 
     979                 :             || VSIStatL( psPam->pszPamFilename, &sStatBuf ) == 0) )
     980                 :     {
     981             186 :         papszFileList = CSLAddString( papszFileList, psPam->pszPamFilename );
     982                 :     }
     983                 : 
     984            1320 :     return papszFileList;
     985                 : }
     986                 : 
     987                 : /************************************************************************/
     988                 : /*                          IBuildOverviews()                           */
     989                 : /************************************************************************/
     990                 : 
     991                 : CPLErr GDALPamDataset::IBuildOverviews( const char *pszResampling, 
     992                 :                                         int nOverviews, int *panOverviewList, 
     993                 :                                         int nListBands, int *panBandList,
     994                 :                                         GDALProgressFunc pfnProgress, 
     995              13 :                                         void * pProgressData )
     996                 :     
     997                 : {
     998                 : /* -------------------------------------------------------------------- */
     999                 : /*      Initialize PAM.                                                 */
    1000                 : /* -------------------------------------------------------------------- */
    1001              13 :     PamInitialize();
    1002              13 :     if( psPam == NULL )
    1003               0 :         return CE_None;
    1004                 : 
    1005                 : /* -------------------------------------------------------------------- */
    1006                 : /*      If we appear to have subdatasets and to have a physical         */
    1007                 : /*      filename, use that physical filename to derive a name for a     */
    1008                 : /*      new overview file.                                              */
    1009                 : /* -------------------------------------------------------------------- */
    1010              13 :     if( oOvManager.IsInitialized() && psPam->osPhysicalFilename.length() != 0 )
    1011                 :         return oOvManager.BuildOverviewsSubDataset( 
    1012                 :             psPam->osPhysicalFilename, pszResampling, 
    1013                 :             nOverviews, panOverviewList,
    1014                 :             nListBands, panBandList,
    1015               4 :             pfnProgress, pProgressData );
    1016                 :     else 
    1017                 :         return GDALDataset::IBuildOverviews( pszResampling, 
    1018                 :                                              nOverviews, panOverviewList, 
    1019                 :                                              nListBands, panBandList, 
    1020               9 :                                              pfnProgress, pProgressData );
    1021                 : }
    1022                 : 
    1023                 : 
    1024                 : /************************************************************************/
    1025                 : /*                          GetProjectionRef()                          */
    1026                 : /************************************************************************/
    1027                 : 
    1028            3886 : const char *GDALPamDataset::GetProjectionRef()
    1029                 : 
    1030                 : {
    1031            3886 :     if( psPam && psPam->pszProjection )
    1032               4 :         return psPam->pszProjection;
    1033                 :     else
    1034            3882 :         return GDALDataset::GetProjectionRef();
    1035                 : }
    1036                 : 
    1037                 : /************************************************************************/
    1038                 : /*                           SetProjection()                            */
    1039                 : /************************************************************************/
    1040                 : 
    1041             219 : CPLErr GDALPamDataset::SetProjection( const char *pszProjectionIn )
    1042                 : 
    1043                 : {
    1044             219 :     PamInitialize();
    1045                 : 
    1046             219 :     if( psPam == NULL )
    1047               0 :         return GDALDataset::SetProjection( pszProjectionIn );
    1048                 :     else
    1049                 :     {
    1050             219 :         CPLFree( psPam->pszProjection );
    1051             219 :         psPam->pszProjection = CPLStrdup( pszProjectionIn );
    1052             219 :         MarkPamDirty();
    1053                 : 
    1054             219 :         return CE_None;
    1055                 :     }
    1056                 : }
    1057                 : 
    1058                 : /************************************************************************/
    1059                 : /*                          GetGeoTransform()                           */
    1060                 : /************************************************************************/
    1061                 : 
    1062            3596 : CPLErr GDALPamDataset::GetGeoTransform( double * padfTransform )
    1063                 : 
    1064                 : {
    1065            3596 :     if( psPam && psPam->bHaveGeoTransform )
    1066                 :     {
    1067               1 :         memcpy( padfTransform, psPam->adfGeoTransform, sizeof(double) * 6 );
    1068               1 :         return CE_None;
    1069                 :     }
    1070                 :     else
    1071            3595 :         return GDALDataset::GetGeoTransform( padfTransform );
    1072                 : }
    1073                 : 
    1074                 : /************************************************************************/
    1075                 : /*                          SetGeoTransform()                           */
    1076                 : /************************************************************************/
    1077                 : 
    1078             174 : CPLErr GDALPamDataset::SetGeoTransform( double * padfTransform )
    1079                 : 
    1080                 : {
    1081             174 :     PamInitialize();
    1082                 : 
    1083             174 :     if( psPam )
    1084                 :     {
    1085             174 :         MarkPamDirty();
    1086             174 :         psPam->bHaveGeoTransform = TRUE;
    1087             174 :         memcpy( psPam->adfGeoTransform, padfTransform, sizeof(double) * 6 );
    1088             174 :         return( CE_None );
    1089                 :     }
    1090                 :     else
    1091                 :     {
    1092               0 :         return GDALDataset::SetGeoTransform( padfTransform );
    1093                 :     }
    1094                 : }
    1095                 : 
    1096                 : /************************************************************************/
    1097                 : /*                            GetGCPCount()                             */
    1098                 : /************************************************************************/
    1099                 : 
    1100            3529 : int GDALPamDataset::GetGCPCount()
    1101                 : 
    1102                 : {
    1103            3529 :     if( psPam && psPam->nGCPCount > 0 )
    1104               2 :         return psPam->nGCPCount;
    1105                 :     else
    1106            3527 :         return GDALDataset::GetGCPCount();
    1107                 : }
    1108                 : 
    1109                 : /************************************************************************/
    1110                 : /*                          GetGCPProjection()                          */
    1111                 : /************************************************************************/
    1112                 : 
    1113               2 : const char *GDALPamDataset::GetGCPProjection()
    1114                 : 
    1115                 : {
    1116               2 :     if( psPam && psPam->pszGCPProjection != NULL )
    1117               2 :         return psPam->pszGCPProjection;
    1118                 :     else
    1119               0 :         return GDALDataset::GetGCPProjection();
    1120                 : }
    1121                 : 
    1122                 : /************************************************************************/
    1123                 : /*                               GetGCPs()                              */
    1124                 : /************************************************************************/
    1125                 : 
    1126               2 : const GDAL_GCP *GDALPamDataset::GetGCPs()
    1127                 : 
    1128                 : {
    1129               2 :     if( psPam && psPam->nGCPCount > 0 )
    1130               2 :         return psPam->pasGCPList;
    1131                 :     else
    1132               0 :         return GDALDataset::GetGCPs();
    1133                 : }
    1134                 : 
    1135                 : /************************************************************************/
    1136                 : /*                              SetGCPs()                               */
    1137                 : /************************************************************************/
    1138                 : 
    1139                 : CPLErr GDALPamDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
    1140               0 :                                 const char *pszGCPProjection )
    1141                 : 
    1142                 : {
    1143               0 :     PamInitialize();
    1144                 : 
    1145               0 :     if( psPam )
    1146                 :     {
    1147               0 :         CPLFree( psPam->pszGCPProjection );
    1148               0 :         if( psPam->nGCPCount > 0 )
    1149                 :         {
    1150               0 :             GDALDeinitGCPs( psPam->nGCPCount, psPam->pasGCPList );
    1151               0 :             CPLFree( psPam->pasGCPList );
    1152                 :         }
    1153                 : 
    1154               0 :         psPam->pszGCPProjection = CPLStrdup(pszGCPProjection);
    1155               0 :         psPam->nGCPCount = nGCPCount;
    1156               0 :         psPam->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
    1157                 : 
    1158               0 :         MarkPamDirty();
    1159                 : 
    1160               0 :         return CE_None;
    1161                 :     }
    1162                 :     else
    1163                 :     {
    1164               0 :         return GDALDataset::SetGCPs( nGCPCount, pasGCPList, pszGCPProjection );
    1165                 :     }
    1166                 : }
    1167                 : 
    1168                 : /************************************************************************/
    1169                 : /*                            SetMetadata()                             */
    1170                 : /************************************************************************/
    1171                 : 
    1172                 : CPLErr GDALPamDataset::SetMetadata( char **papszMetadata, 
    1173            1483 :                                     const char *pszDomain )
    1174                 : 
    1175                 : {
    1176            1483 :     PamInitialize();
    1177                 : 
    1178            1483 :     if( psPam )
    1179            1483 :         MarkPamDirty();
    1180                 : 
    1181            1483 :     return GDALDataset::SetMetadata( papszMetadata, pszDomain );
    1182                 : }
    1183                 : 
    1184                 : /************************************************************************/
    1185                 : /*                          SetMetadataItem()                           */
    1186                 : /************************************************************************/
    1187                 : 
    1188                 : CPLErr GDALPamDataset::SetMetadataItem( const char *pszName, 
    1189                 :                                         const char *pszValue, 
    1190            3032 :                                         const char *pszDomain )
    1191                 : 
    1192                 : {
    1193            3032 :     PamInitialize();
    1194                 : 
    1195            3032 :     if( psPam )
    1196            3032 :         MarkPamDirty();
    1197                 : 
    1198            3032 :     return GDALDataset::SetMetadataItem( pszName, pszValue, pszDomain );
    1199                 : }
    1200                 : 
    1201                 : /************************************************************************/
    1202                 : /*                          GetMetadataItem()                           */
    1203                 : /************************************************************************/
    1204                 : 
    1205                 : const char *GDALPamDataset::GetMetadataItem( const char *pszName, 
    1206            3137 :                                              const char *pszDomain )
    1207                 : 
    1208                 : {
    1209                 : /* -------------------------------------------------------------------- */
    1210                 : /*      A request against the ProxyOverviewRequest is a special         */
    1211                 : /*      mechanism to request an overview filename be allocated in       */
    1212                 : /*      the proxy pool location.  The allocated name is saved as        */
    1213                 : /*      metadata as well as being returned.                             */
    1214                 : /* -------------------------------------------------------------------- */
    1215            3137 :     if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
    1216                 :     {
    1217               2 :         CPLString osPrelimOvr = GetDescription();
    1218               2 :         osPrelimOvr += ":::OVR";
    1219                 :         
    1220               2 :         const char *pszProxyOvrFilename = PamAllocateProxy( osPrelimOvr );
    1221               2 :         if( pszProxyOvrFilename == NULL )
    1222               4 :             return NULL;
    1223                 :         
    1224               0 :         SetMetadataItem( "OVERVIEW_FILE", pszProxyOvrFilename, "OVERVIEWS" );
    1225                 :         
    1226               0 :         return pszProxyOvrFilename;
    1227                 :     }
    1228                 : 
    1229                 : /* -------------------------------------------------------------------- */
    1230                 : /*      If the OVERVIEW_FILE metadata is requested, we intercept the    */
    1231                 : /*      request in order to replace ":::BASE:::" with the path to       */
    1232                 : /*      the physical file - if available.  This is primarily for the    */
    1233                 : /*      purpose of managing subdataset overview filenames as being      */
    1234                 : /*      relative to the physical file the subdataset comes              */
    1235                 : /*      from. (#3287).                                                  */
    1236                 : /* -------------------------------------------------------------------- */
    1237            3135 :     else if( pszDomain != NULL 
    1238                 :              && EQUAL(pszDomain,"OVERVIEWS") 
    1239                 :              && EQUAL(pszName,"OVERVIEW_FILE") )
    1240                 :     {
    1241                 :         const char *pszOverviewFile = 
    1242             968 :             GDALDataset::GetMetadataItem( pszName, pszDomain );
    1243                 : 
    1244             968 :         if( pszOverviewFile == NULL 
    1245                 :             || !EQUALN(pszOverviewFile,":::BASE:::",10) )
    1246             958 :             return pszOverviewFile;
    1247                 :         
    1248              10 :         CPLString osPath;
    1249                 : 
    1250              10 :         if( strlen(GetPhysicalFilename()) > 0 )
    1251              10 :             osPath = CPLGetPath(GetPhysicalFilename());
    1252                 :         else
    1253               0 :             osPath = CPLGetPath(GetDescription());
    1254                 : 
    1255              10 :         return CPLFormFilename( osPath, pszOverviewFile + 10, NULL );
    1256                 :     }
    1257                 : 
    1258                 : /* -------------------------------------------------------------------- */
    1259                 : /*      Everything else is a pass through.                              */
    1260                 : /* -------------------------------------------------------------------- */
    1261                 :     else
    1262            2167 :         return GDALDataset::GetMetadataItem( pszName, pszDomain );
    1263                 : 
    1264                 : }
    1265                 : 
    1266                 : /************************************************************************/
    1267                 : /*                            GetMetadata()                             */
    1268                 : /************************************************************************/
    1269                 : 
    1270             598 : char **GDALPamDataset::GetMetadata( const char *pszDomain )
    1271                 : 
    1272                 : {
    1273                 : //    if( pszDomain == NULL || !EQUAL(pszDomain,"ProxyOverviewRequest") )
    1274             598 :         return GDALDataset::GetMetadata( pszDomain );
    1275                 : }
    1276                 : 
    1277                 : /************************************************************************/
    1278                 : /*                             TryLoadAux()                             */
    1279                 : /************************************************************************/
    1280                 : 
    1281            5477 : CPLErr GDALPamDataset::TryLoadAux()
    1282                 : 
    1283                 : {
    1284                 : /* -------------------------------------------------------------------- */
    1285                 : /*      Initialize PAM.                                                 */
    1286                 : /* -------------------------------------------------------------------- */
    1287            5477 :     PamInitialize();
    1288            5477 :     if( psPam == NULL )
    1289               0 :         return CE_None;
    1290                 : 
    1291                 : /* -------------------------------------------------------------------- */
    1292                 : /*      What is the name of the physical file we are referencing?       */
    1293                 : /*      We allow an override via the psPam->pszPhysicalFile item.       */
    1294                 : /* -------------------------------------------------------------------- */
    1295            5477 :     const char *pszPhysicalFile = psPam->osPhysicalFilename;
    1296                 : 
    1297            5477 :     if( strlen(pszPhysicalFile) == 0 && GetDescription() != NULL )
    1298            5164 :         pszPhysicalFile = GetDescription();
    1299                 : 
    1300            5477 :     if( strlen(pszPhysicalFile) == 0 )
    1301               0 :         return CE_None;
    1302                 : 
    1303                 : /* -------------------------------------------------------------------- */
    1304                 : /*      Try to open .aux file.                                          */
    1305                 : /* -------------------------------------------------------------------- */
    1306                 :     GDALDataset *poAuxDS = GDALFindAssociatedAuxFile( pszPhysicalFile, 
    1307            5477 :                                                       GA_ReadOnly, this );
    1308                 : 
    1309            5477 :     if( poAuxDS == NULL )
    1310            5474 :         return CE_None;
    1311                 : 
    1312                 : /* -------------------------------------------------------------------- */
    1313                 : /*      Do we have an SRS on the aux file?                              */
    1314                 : /* -------------------------------------------------------------------- */
    1315               3 :     if( strlen(poAuxDS->GetProjectionRef()) > 0 )
    1316               0 :         GDALPamDataset::SetProjection( poAuxDS->GetProjectionRef() );
    1317                 : 
    1318                 : /* -------------------------------------------------------------------- */
    1319                 : /*      Geotransform.                                                   */
    1320                 : /* -------------------------------------------------------------------- */
    1321               3 :     if( poAuxDS->GetGeoTransform( psPam->adfGeoTransform ) == CE_None )
    1322               0 :         psPam->bHaveGeoTransform = TRUE;
    1323                 : 
    1324                 : /* -------------------------------------------------------------------- */
    1325                 : /*      GCPs                                                            */
    1326                 : /* -------------------------------------------------------------------- */
    1327               3 :     if( poAuxDS->GetGCPCount() > 0 )
    1328                 :     {
    1329               0 :         psPam->nGCPCount = poAuxDS->GetGCPCount();
    1330                 :         psPam->pasGCPList = GDALDuplicateGCPs( psPam->nGCPCount, 
    1331               0 :                                                poAuxDS->GetGCPs() );
    1332                 :     }
    1333                 : 
    1334                 : /* -------------------------------------------------------------------- */
    1335                 : /*      Apply metadata. We likely ought to be merging this in rather    */
    1336                 : /*      than overwriting everything that was there.                     */
    1337                 : /* -------------------------------------------------------------------- */
    1338               3 :     char **papszMD = poAuxDS->GetMetadata();
    1339               3 :     if( CSLCount(papszMD) > 0 )
    1340                 :     {
    1341                 :         char **papszMerged = 
    1342               0 :             CSLMerge( CSLDuplicate(GetMetadata()), papszMD );
    1343               0 :         GDALPamDataset::SetMetadata( papszMerged );
    1344               0 :         CSLDestroy( papszMerged );
    1345                 :     }
    1346                 : 
    1347               3 :     papszMD = poAuxDS->GetMetadata("XFORMS");
    1348               3 :     if( CSLCount(papszMD) > 0 )
    1349                 :     {
    1350                 :         char **papszMerged = 
    1351               0 :             CSLMerge( CSLDuplicate(GetMetadata("XFORMS")), papszMD );
    1352               0 :         GDALPamDataset::SetMetadata( papszMerged, "XFORMS" );
    1353               0 :         CSLDestroy( papszMerged );
    1354                 :     }
    1355                 : 
    1356                 : /* ==================================================================== */
    1357                 : /*      Process bands.                                                  */
    1358                 : /* ==================================================================== */
    1359                 :     int iBand;
    1360                 : 
    1361               6 :     for( iBand = 0; iBand < poAuxDS->GetRasterCount(); iBand++ )
    1362                 :     {
    1363               3 :         if( iBand >= GetRasterCount() )
    1364               0 :             break;
    1365                 : 
    1366               3 :         GDALRasterBand *poAuxBand = poAuxDS->GetRasterBand( iBand+1 );
    1367               3 :         GDALRasterBand *poBand = GetRasterBand( iBand+1 );
    1368                 : 
    1369               3 :         papszMD = poAuxBand->GetMetadata();
    1370               3 :         if( CSLCount(papszMD) > 0 )
    1371                 :         {
    1372                 :             char **papszMerged = 
    1373               3 :                 CSLMerge( CSLDuplicate(poBand->GetMetadata()), papszMD );
    1374               3 :             poBand->SetMetadata( papszMerged );
    1375               3 :             CSLDestroy( papszMerged );
    1376                 :         }
    1377                 : 
    1378               3 :         if( poAuxBand->GetCategoryNames() != NULL )
    1379               0 :             poBand->SetCategoryNames( poAuxBand->GetCategoryNames() );
    1380                 : 
    1381               3 :         if( poAuxBand->GetColorTable() != NULL 
    1382                 :             && poBand->GetColorTable() == NULL )
    1383               0 :             poBand->SetColorTable( poAuxBand->GetColorTable() );
    1384                 : 
    1385                 :         // histograms?
    1386                 :         double dfMin, dfMax;
    1387               3 :         int nBuckets, *panHistogram=NULL;
    1388                 : 
    1389               3 :         if( poAuxBand->GetDefaultHistogram( &dfMin, &dfMax, 
    1390                 :                                             &nBuckets, &panHistogram,
    1391                 :                                             FALSE, NULL, NULL ) == CE_None )
    1392                 :         {
    1393                 :             poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, 
    1394               1 :                                          panHistogram );
    1395               1 :             CPLFree( panHistogram );
    1396                 :         }
    1397                 : 
    1398                 :         // RAT 
    1399               3 :         if( poAuxBand->GetDefaultRAT() != NULL )
    1400               1 :             poBand->SetDefaultRAT( poAuxBand->GetDefaultRAT() );
    1401                 : 
    1402                 :         // NoData
    1403               3 :         int bSuccess = FALSE;
    1404               3 :         double dfNoDataValue = poAuxBand->GetNoDataValue( &bSuccess );
    1405               3 :         if( bSuccess )
    1406               3 :             poBand->SetNoDataValue( dfNoDataValue );
    1407                 :     }
    1408                 : 
    1409               3 :     GDALClose( poAuxDS );
    1410                 :     
    1411                 : /* -------------------------------------------------------------------- */
    1412                 : /*      Mark PAM info as clean.                                         */
    1413                 : /* -------------------------------------------------------------------- */
    1414               3 :     nPamFlags &= ~GPF_DIRTY;
    1415                 : 
    1416               3 :     return CE_Failure;
    1417                 : }

Generated by: LTP GCOV extension version 1.5