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