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 : }
|