1 : /******************************************************************************
2 : * $Id: pdsdataset.cpp 19982 2010-07-06 18:10:00Z rouault $
3 : *
4 : * Project: PDS Driver; Planetary Data System Format
5 : * Purpose: Implementation of PDSDataset
6 : * Author: Trent Hare (thare@usgs.gov),
7 : * Robert Soricone (rsoricone@usgs.gov)
8 : *
9 : * NOTE: Original code authored by Trent and Robert and placed in the public
10 : * domain as per US government policy. I have (within my rights) appropriated
11 : * it and placed it under the following license. This is not intended to
12 : * diminish Trent and Roberts contribution.
13 : ******************************************************************************
14 : * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
15 : *
16 : * Permission is hereby granted, free of charge, to any person obtaining a
17 : * copy of this software and associated documentation files (the "Software"),
18 : * to deal in the Software without restriction, including without limitation
19 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 : * and/or sell copies of the Software, and to permit persons to whom the
21 : * Software is furnished to do so, subject to the following conditions:
22 : *
23 : * The above copyright notice and this permission notice shall be included
24 : * in all copies or substantial portions of the Software.
25 : *
26 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 : * DEALINGS IN THE SOFTWARE.
33 : ****************************************************************************/
34 :
35 : // Set up PDS NULL values
36 : #define NULL1 0
37 : #define NULL2 -32768
38 : //#define NULL3 -0.3402822655089E+39
39 : //Same as ESRI_GRID_FLOAT_NO_DATA
40 : //#define NULL3 -340282346638528859811704183484516925440.0
41 : #define NULL3 -3.4028226550889044521e+38
42 :
43 : #include "rawdataset.h"
44 : #include "gdal_proxy.h"
45 : #include "ogr_spatialref.h"
46 : #include "cpl_string.h"
47 : #include "nasakeywordhandler.h"
48 :
49 : CPL_CVSID("$Id: pdsdataset.cpp 19982 2010-07-06 18:10:00Z rouault $");
50 :
51 : CPL_C_START
52 : void GDALRegister_PDS(void);
53 : CPL_C_END
54 :
55 : /************************************************************************/
56 : /* ==================================================================== */
57 : /* PDSDataset */
58 : /* ==================================================================== */
59 : /************************************************************************/
60 :
61 : class PDSDataset : public RawDataset
62 : {
63 : FILE *fpImage; // image data file.
64 : GDALDataset *poCompressedDS;
65 :
66 : NASAKeywordHandler oKeywords;
67 :
68 : int bGotTransform;
69 : double adfGeoTransform[6];
70 :
71 : CPLString osProjection;
72 :
73 : CPLString osTempResult;
74 :
75 : void ParseSRS();
76 : int ParseUncompressedImage();
77 : int ParseCompressedImage();
78 : void CleanString( CPLString &osInput );
79 :
80 : const char *GetKeyword( const char *pszPath,
81 : const char *pszDefault = "");
82 : const char *GetKeywordSub( const char *pszPath,
83 : int iSubscript,
84 : const char *pszDefault = "");
85 : const char *GetKeywordUnit( const char *pszPath,
86 : int iSubscript,
87 : const char *pszDefault = "");
88 :
89 : public:
90 : PDSDataset();
91 : ~PDSDataset();
92 :
93 : virtual CPLErr GetGeoTransform( double * padfTransform );
94 : virtual const char *GetProjectionRef(void);
95 :
96 : virtual char **GetFileList(void);
97 :
98 : virtual CPLErr IBuildOverviews( const char *, int, int *,
99 : int, int *, GDALProgressFunc, void * );
100 :
101 : virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
102 : void *, int, int, GDALDataType,
103 : int, int *, int, int, int );
104 :
105 : static int Identify( GDALOpenInfo * );
106 : static GDALDataset *Open( GDALOpenInfo * );
107 : static GDALDataset *Create( const char * pszFilename,
108 : int nXSize, int nYSize, int nBands,
109 : GDALDataType eType, char ** papszParmList );
110 : };
111 :
112 : /************************************************************************/
113 : /* PDSDataset() */
114 : /************************************************************************/
115 :
116 9 : PDSDataset::PDSDataset()
117 : {
118 9 : fpImage = NULL;
119 9 : bGotTransform = FALSE;
120 9 : adfGeoTransform[0] = 0.0;
121 9 : adfGeoTransform[1] = 1.0;
122 9 : adfGeoTransform[2] = 0.0;
123 9 : adfGeoTransform[3] = 0.0;
124 9 : adfGeoTransform[4] = 0.0;
125 9 : adfGeoTransform[5] = 1.0;
126 9 : poCompressedDS = NULL;
127 9 : }
128 :
129 : /************************************************************************/
130 : /* ~PDSDataset() */
131 : /************************************************************************/
132 :
133 9 : PDSDataset::~PDSDataset()
134 :
135 : {
136 9 : FlushCache();
137 9 : if( fpImage != NULL )
138 7 : VSIFCloseL( fpImage );
139 :
140 9 : if( poCompressedDS )
141 2 : delete poCompressedDS;
142 9 : }
143 :
144 : /************************************************************************/
145 : /* GetFileList() */
146 : /************************************************************************/
147 :
148 1 : char **PDSDataset::GetFileList()
149 :
150 : {
151 1 : char **papszFileList = RawDataset::GetFileList();
152 :
153 1 : if( poCompressedDS != NULL )
154 : {
155 1 : char **papszCFileList = poCompressedDS->GetFileList();
156 :
157 : papszFileList = CSLInsertStrings( papszFileList, -1,
158 1 : papszCFileList );
159 1 : CSLDestroy( papszCFileList );
160 : }
161 :
162 1 : return papszFileList;
163 : }
164 :
165 : /************************************************************************/
166 : /* IBuildOverviews() */
167 : /************************************************************************/
168 :
169 : CPLErr PDSDataset::IBuildOverviews( const char *pszResampling,
170 : int nOverviews, int *panOverviewList,
171 : int nListBands, int *panBandList,
172 : GDALProgressFunc pfnProgress,
173 0 : void * pProgressData )
174 : {
175 0 : if( poCompressedDS != NULL )
176 : return poCompressedDS->BuildOverviews( pszResampling,
177 : nOverviews, panOverviewList,
178 : nListBands, panBandList,
179 0 : pfnProgress, pProgressData );
180 : else
181 : return RawDataset::IBuildOverviews( pszResampling,
182 : nOverviews, panOverviewList,
183 : nListBands, panBandList,
184 0 : pfnProgress, pProgressData );
185 : }
186 :
187 : /************************************************************************/
188 : /* IRasterIO() */
189 : /************************************************************************/
190 :
191 : CPLErr PDSDataset::IRasterIO( GDALRWFlag eRWFlag,
192 : int nXOff, int nYOff, int nXSize, int nYSize,
193 : void * pData, int nBufXSize, int nBufYSize,
194 : GDALDataType eBufType,
195 : int nBandCount, int *panBandMap,
196 0 : int nPixelSpace, int nLineSpace, int nBandSpace)
197 :
198 : {
199 0 : if( poCompressedDS != NULL )
200 : return poCompressedDS->RasterIO( eRWFlag,
201 : nXOff, nYOff, nXSize, nYSize,
202 : pData, nBufXSize, nBufYSize,
203 : eBufType, nBandCount, panBandMap,
204 0 : nPixelSpace, nLineSpace, nBandSpace );
205 : else
206 : return RawDataset::IRasterIO( eRWFlag,
207 : nXOff, nYOff, nXSize, nYSize,
208 : pData, nBufXSize, nBufYSize,
209 : eBufType, nBandCount, panBandMap,
210 0 : nPixelSpace, nLineSpace, nBandSpace );
211 : }
212 :
213 : /************************************************************************/
214 : /* GetProjectionRef() */
215 : /************************************************************************/
216 :
217 3 : const char *PDSDataset::GetProjectionRef()
218 :
219 : {
220 3 : if( strlen(osProjection) > 0 )
221 3 : return osProjection;
222 : else
223 0 : return GDALPamDataset::GetProjectionRef();
224 : }
225 :
226 : /************************************************************************/
227 : /* GetGeoTransform() */
228 : /************************************************************************/
229 :
230 2 : CPLErr PDSDataset::GetGeoTransform( double * padfTransform )
231 :
232 : {
233 2 : if( bGotTransform )
234 : {
235 2 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
236 2 : return CE_None;
237 : }
238 : else
239 : {
240 0 : return GDALPamDataset::GetGeoTransform( padfTransform );
241 : }
242 : }
243 :
244 : /************************************************************************/
245 : /* ParseSRS() */
246 : /************************************************************************/
247 :
248 9 : void PDSDataset::ParseSRS()
249 :
250 : {
251 9 : const char *pszFilename = GetDescription();
252 :
253 : /* ==================================================================== */
254 : /* Get the geotransform. */
255 : /* ==================================================================== */
256 : /*********** Grab Cellsize ************/
257 : //example:
258 : //MAP_SCALE = 14.818 <KM/PIXEL>
259 : //added search for unit (only checks for CM, KM - defaults to Meters)
260 : const char *value;
261 : //Georef parameters
262 9 : double dfULXMap=0.5;
263 9 : double dfULYMap = 0.5;
264 9 : double dfXDim = 1.0;
265 9 : double dfYDim = 1.0;
266 9 : double xulcenter = 0.0;
267 9 : double yulcenter = 0.0;
268 :
269 9 : value = GetKeyword("IMAGE_MAP_PROJECTION.MAP_SCALE");
270 9 : if (strlen(value) > 0 ) {
271 7 : dfXDim = (float) atof(value);
272 7 : dfYDim = (float) atof(value) * -1;
273 :
274 7 : CPLString unit = GetKeywordUnit("IMAGE_MAP_PROJECTION.MAP_SCALE",2); //KM
275 : //value = GetKeywordUnit("IMAGE_MAP_PROJECTION.MAP_SCALE",3); //PIXEL
276 7 : if((EQUAL(unit,"M")) || (EQUAL(unit,"METER")) || (EQUAL(unit,"METERS"))) {
277 : // do nothing
278 : }
279 3 : else if (EQUAL(unit,"CM")) {
280 : // convert from cm to m
281 0 : dfXDim = dfXDim / 100.0;
282 0 : dfYDim = dfYDim / 100.0;
283 : } else {
284 : //defaults to convert km to m
285 3 : dfXDim = dfXDim * 1000.0;
286 3 : dfYDim = dfYDim * 1000.0;
287 7 : }
288 : }
289 :
290 : // Calculate upper left corner of pixel in meters from the upper left center pixel which
291 : // should be correct for what is documented in the PDS manual
292 : // It doesn't mean it will work perfectly for every PDS image, as they tend to be released in different ways.
293 : // both dfULYMap, dfULXMap were update October 11, 2007 to correct 0.5 cellsize offset
294 : /*********** Grab LINE_PROJECTION_OFFSET ************/
295 9 : value = GetKeyword("IMAGE_MAP_PROJECTION.LINE_PROJECTION_OFFSET");
296 9 : if (strlen(value) > 0) {
297 7 : yulcenter = (float) atof(value);
298 7 : dfULYMap = ((yulcenter - 0.5) * dfYDim * -1);
299 : //notice dfYDim is negative here which is why it is negated again
300 : }
301 : /*********** Grab SAMPLE_PROJECTION_OFFSET ************/
302 9 : value = GetKeyword("IMAGE_MAP_PROJECTION.SAMPLE_PROJECTION_OFFSET");
303 9 : if( strlen(value) > 0 ) {
304 7 : xulcenter = (float) atof(value);
305 7 : dfULXMap = ((xulcenter - 0.5) * dfXDim * -1);
306 : }
307 :
308 : /* ==================================================================== */
309 : /* Get the coordinate system. */
310 : /* ==================================================================== */
311 9 : int bProjectionSet = TRUE;
312 9 : double semi_major = 0.0;
313 9 : double semi_minor = 0.0;
314 9 : double iflattening = 0.0;
315 9 : float center_lat = 0.0;
316 9 : float center_lon = 0.0;
317 9 : float first_std_parallel = 0.0;
318 9 : float second_std_parallel = 0.0;
319 9 : OGRSpatialReference oSRS;
320 :
321 : /*********** Grab TARGET_NAME ************/
322 : /**** This is the planets name i.e. MARS ***/
323 9 : CPLString target_name = GetKeyword("TARGET_NAME");
324 9 : CleanString( target_name );
325 :
326 : /********** Grab MAP_PROJECTION_TYPE *****/
327 : CPLString map_proj_name =
328 9 : GetKeyword( "IMAGE_MAP_PROJECTION.MAP_PROJECTION_TYPE");
329 9 : CleanString( map_proj_name );
330 :
331 : /****** Grab semi_major & convert to KM ******/
332 : semi_major =
333 9 : atof(GetKeyword( "IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) * 1000.0;
334 :
335 : /****** Grab semi-minor & convert to KM ******/
336 : semi_minor =
337 9 : atof(GetKeyword( "IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) * 1000.0;
338 :
339 : /*********** Grab CENTER_LAT ************/
340 : center_lat =
341 9 : atof(GetKeyword( "IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
342 :
343 : /*********** Grab CENTER_LON ************/
344 : center_lon =
345 9 : atof(GetKeyword( "IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
346 :
347 : /********** Grab 1st std parallel *******/
348 : first_std_parallel =
349 9 : atof(GetKeyword( "IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
350 :
351 : /********** Grab 2nd std parallel *******/
352 : second_std_parallel =
353 9 : atof(GetKeyword( "IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
354 :
355 : /*** grab PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
356 : // Need to further study how ocentric/ographic will effect the gdal library.
357 : // So far we will use this fact to define a sphere or ellipse for some projections
358 : // Frank - may need to talk this over
359 9 : char bIsGeographic = TRUE;
360 9 : value = GetKeyword("IMAGE_MAP_PROJECTION.COORDINATE_SYSTEM_NAME");
361 9 : if (EQUAL( value, "PLANETOCENTRIC" ))
362 4 : bIsGeographic = FALSE;
363 :
364 : /** Set oSRS projection and parameters --- all PDS supported types added if apparently supported in oSRS
365 : "AITOFF", ** Not supported in GDAL??
366 : "ALBERS",
367 : "BONNE",
368 : "BRIESEMEISTER", ** Not supported in GDAL??
369 : "CYLINDRICAL EQUAL AREA",
370 : "EQUIDISTANT",
371 : "EQUIRECTANGULAR",
372 : "GNOMONIC",
373 : "HAMMER", ** Not supported in GDAL??
374 : "HENDU", ** Not supported in GDAL??
375 : "LAMBERT AZIMUTHAL EQUAL AREA",
376 : "LAMBERT CONFORMAL",
377 : "MERCATOR",
378 : "MOLLWEIDE",
379 : "OBLIQUE CYLINDRICAL",
380 : "ORTHOGRAPHIC",
381 : "SIMPLE CYLINDRICAL",
382 : "SINUSOIDAL",
383 : "STEREOGRAPHIC",
384 : "TRANSVERSE MERCATOR",
385 : "VAN DER GRINTEN", ** Not supported in GDAL??
386 : "WERNER" ** Not supported in GDAL??
387 : **/
388 9 : CPLDebug( "PDS","using projection %s\n\n", map_proj_name.c_str());
389 :
390 9 : if ((EQUAL( map_proj_name, "EQUIRECTANGULAR" )) ||
391 : (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) ||
392 : (EQUAL( map_proj_name, "EQUIDISTANT" )) ) {
393 5 : oSRS.SetEquirectangular2 ( 0.0, center_lon, center_lat, 0, 0 );
394 4 : } else if (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) {
395 0 : oSRS.SetOrthographic ( center_lat, center_lon, 0, 0 );
396 4 : } else if (EQUAL( map_proj_name, "SINUSOIDAL" )) {
397 2 : oSRS.SetSinusoidal ( center_lon, 0, 0 );
398 2 : } else if (EQUAL( map_proj_name, "MERCATOR" )) {
399 0 : oSRS.SetMercator ( center_lat, center_lon, 1, 0, 0 );
400 2 : } else if (EQUAL( map_proj_name, "STEREOGRAPHIC" )) {
401 0 : oSRS.SetStereographic ( center_lat, center_lon, 1, 0, 0 );
402 2 : } else if (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC")) {
403 0 : oSRS.SetPS ( center_lat, center_lon, 1, 0, 0 );
404 2 : } else if (EQUAL( map_proj_name, "TRANSVERSE_MERCATOR" )) {
405 0 : oSRS.SetTM ( center_lat, center_lon, 1, 0, 0 );
406 2 : } else if (EQUAL( map_proj_name, "LAMBERT_CONFORMAL_CONIC" )) {
407 : oSRS.SetLCC ( first_std_parallel, second_std_parallel,
408 0 : center_lat, center_lon, 0, 0 );
409 2 : } else if (EQUAL( map_proj_name, "LAMBERT_AZIMUTHAL_EQUAL_AREA" )) {
410 0 : oSRS.SetLAEA( center_lat, center_lon, 0, 0 );
411 2 : } else if (EQUAL( map_proj_name, "CYLINDRICAL_EQUAL_AREA" )) {
412 0 : oSRS.SetCEA ( first_std_parallel, center_lon, 0, 0 );
413 2 : } else if (EQUAL( map_proj_name, "MOLLWEIDE" )) {
414 0 : oSRS.SetMollweide ( center_lon, 0, 0 );
415 2 : } else if (EQUAL( map_proj_name, "ALBERS" )) {
416 : oSRS.SetACEA ( first_std_parallel, second_std_parallel,
417 0 : center_lat, center_lon, 0, 0 );
418 2 : } else if (EQUAL( map_proj_name, "BONNE" )) {
419 0 : oSRS.SetBonne ( first_std_parallel, center_lon, 0, 0 );
420 2 : } else if (EQUAL( map_proj_name, "GNOMONIC" )) {
421 0 : oSRS.SetGnomonic ( center_lat, center_lon, 0, 0 );
422 2 : } else if (EQUAL( map_proj_name, "OBLIQUE_CYLINDRICAL" )) {
423 : // hope Swiss Oblique Cylindrical is the same
424 0 : oSRS.SetSOC ( center_lat, center_lon, 0, 0 );
425 : } else {
426 : CPLDebug( "PDS",
427 : "Dataset projection %s is not supported. Continuing...",
428 2 : map_proj_name.c_str() );
429 2 : bProjectionSet = FALSE;
430 : }
431 :
432 9 : if (bProjectionSet) {
433 : //Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword
434 7 : CPLString proj_target_name = map_proj_name + " " + target_name;
435 7 : oSRS.SetProjCS(proj_target_name); //set ProjCS keyword
436 :
437 : //The geographic/geocentric name will be the same basic name as the body name
438 : //'GCS' = Geographic/Geocentric Coordinate System
439 7 : CPLString geog_name = "GCS_" + target_name;
440 :
441 : //The datum and sphere names will be the same basic name aas the planet
442 7 : CPLString datum_name = "D_" + target_name;
443 7 : CPLString sphere_name = target_name; // + "_IAU_IAG"); //Might not be IAU defined so don't add
444 :
445 : //calculate inverse flattening from major and minor axis: 1/f = a/(a-b)
446 7 : if ((semi_major - semi_minor) < 0.0000001)
447 6 : iflattening = 0;
448 : else
449 1 : iflattening = semi_major / (semi_major - semi_minor);
450 :
451 : //Set the body size but take into consideration which proj is being used to help w/ compatibility
452 : //Notice that most PDS projections are spherical based on the fact that ISIS/PICS are spherical
453 : //Set the body size but take into consideration which proj is being used to help w/ proj4 compatibility
454 : //The use of a Sphere, polar radius or ellipse here is based on how ISIS does it internally
455 7 : if ( ( (EQUAL( map_proj_name, "STEREOGRAPHIC" ) && (fabs(center_lat) == 90)) ) ||
456 : (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC" )))
457 : {
458 0 : if (bIsGeographic) {
459 : //Geograpraphic, so set an ellipse
460 : oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
461 : semi_major, iflattening,
462 0 : "Reference_Meridian", 0.0 );
463 : } else {
464 : //Geocentric, so force a sphere using the semi-minor axis. I hope...
465 0 : sphere_name += "_polarRadius";
466 : oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
467 : semi_minor, 0.0,
468 0 : "Reference_Meridian", 0.0 );
469 : }
470 : }
471 7 : else if ( (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) ||
472 : (EQUAL( map_proj_name, "EQUIDISTANT" )) ||
473 : (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) ||
474 : (EQUAL( map_proj_name, "STEREOGRAPHIC" )) ||
475 : (EQUAL( map_proj_name, "SINUSOIDAL" )) ) {
476 : //isis uses the spherical equation for these projections so force a sphere
477 : oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
478 : semi_major, 0.0,
479 3 : "Reference_Meridian", 0.0 );
480 : }
481 4 : else if (EQUAL( map_proj_name, "EQUIRECTANGULAR" )) {
482 : //isis uses local radius as a sphere, which is pre-calculated in the PDS label as the semi-major
483 4 : sphere_name += "_localRadius";
484 : oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
485 : semi_major, 0.0,
486 4 : "Reference_Meridian", 0.0 );
487 : }
488 : else {
489 : //All other projections: Mercator, Transverse Mercator, Lambert Conformal, etc.
490 : //Geographic, so set an ellipse
491 0 : if (bIsGeographic) {
492 : oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
493 : semi_major, iflattening,
494 0 : "Reference_Meridian", 0.0 );
495 : } else {
496 : //Geocentric, so force a sphere. I hope...
497 : oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
498 : semi_major, 0.0,
499 0 : "Reference_Meridian", 0.0 );
500 : }
501 : }
502 :
503 : // translate back into a projection string.
504 7 : char *pszResult = NULL;
505 7 : oSRS.exportToWkt( &pszResult );
506 7 : osProjection = pszResult;
507 7 : CPLFree( pszResult );
508 : }
509 :
510 : /* ==================================================================== */
511 : /* Check for a .prj and world file to override the georeferencing. */
512 : /* ==================================================================== */
513 : {
514 9 : CPLString osPath, osName;
515 : FILE *fp;
516 :
517 9 : osPath = CPLGetPath( pszFilename );
518 9 : osName = CPLGetBasename(pszFilename);
519 9 : const char *pszPrjFile = CPLFormCIFilename( osPath, osName, "prj" );
520 :
521 9 : fp = VSIFOpen( pszPrjFile, "r" );
522 9 : if( fp != NULL )
523 : {
524 : char **papszLines;
525 0 : OGRSpatialReference oSRS;
526 :
527 0 : VSIFClose( fp );
528 :
529 0 : papszLines = CSLLoad( pszPrjFile );
530 :
531 0 : if( oSRS.importFromESRI( papszLines ) == OGRERR_NONE )
532 : {
533 0 : char *pszResult = NULL;
534 0 : oSRS.exportToWkt( &pszResult );
535 0 : osProjection = pszResult;
536 0 : CPLFree( pszResult );
537 : }
538 :
539 0 : CSLDestroy( papszLines );
540 9 : }
541 : }
542 :
543 9 : if( dfULYMap != 0.5 || dfULYMap != 0.5 || dfXDim != 1.0 || dfYDim != 1.0 )
544 : {
545 7 : bGotTransform = TRUE;
546 7 : adfGeoTransform[0] = dfULXMap;
547 7 : adfGeoTransform[1] = dfXDim;
548 7 : adfGeoTransform[2] = 0.0;
549 7 : adfGeoTransform[3] = dfULYMap;
550 7 : adfGeoTransform[4] = 0.0;
551 7 : adfGeoTransform[5] = dfYDim;
552 : }
553 :
554 9 : if( !bGotTransform )
555 : bGotTransform =
556 : GDALReadWorldFile( pszFilename, "psw",
557 2 : adfGeoTransform );
558 :
559 9 : if( !bGotTransform )
560 : bGotTransform =
561 : GDALReadWorldFile( pszFilename, "wld",
562 2 : adfGeoTransform );
563 :
564 9 : }
565 :
566 : /************************************************************************/
567 : /* ParseUncompressedImage() */
568 : /************************************************************************/
569 :
570 7 : int PDSDataset::ParseUncompressedImage()
571 :
572 : {
573 : /* ------------------------------------------------------------------- */
574 : /* We assume the user is pointing to the label (ie. .lbl) file. */
575 : /* ------------------------------------------------------------------- */
576 : // IMAGE can be inline or detached and point to an image name
577 : // ^IMAGE = 3
578 : // ^IMAGE = "GLOBAL_ALBEDO_8PPD.IMG"
579 : // ^IMAGE = "MEGT90N000CB.IMG"
580 : // ^IMAGE = ("BLAH.IMG",1) -- start at record 1 (1 based)
581 : // ^IMAGE = ("BLAH.IMG") -- still start at record 1 (equiv of "BLAH.IMG")
582 : // ^IMAGE = ("BLAH.IMG", 5 <BYTES>) -- start at byte 5 (the fifth byte in the file)
583 : // ^IMAGE = 10851 <BYTES>
584 : // ^SPECTRAL_QUBE = 5 for multi-band images
585 :
586 7 : CPLString osImageKeyword = "^IMAGE";
587 7 : CPLString osQube = GetKeyword( osImageKeyword, "" );
588 7 : CPLString osTargetFile = GetDescription();
589 :
590 7 : if (EQUAL(osQube,"")) {
591 0 : osImageKeyword = "^SPECTRAL_QUBE";
592 0 : osQube = GetKeyword( osImageKeyword );
593 : }
594 :
595 7 : int nQube = atoi(osQube);
596 7 : int nDetachedOffset = 0;
597 7 : int bDetachedOffsetInBytes = FALSE;
598 :
599 7 : if( osQube[0] == '(' )
600 : {
601 2 : osQube = "\"";
602 2 : osQube += GetKeywordSub( osImageKeyword, 1 );
603 2 : osQube += "\"";
604 2 : nDetachedOffset = atoi(GetKeywordSub( osImageKeyword, 2, "1")) - 1;
605 :
606 : // If this is not explicitly in bytes, then it is assumed to be in
607 : // records, and we need to translate to bytes.
608 2 : if (strstr(GetKeywordSub(osImageKeyword,2),"<BYTES>") != NULL)
609 1 : bDetachedOffsetInBytes = TRUE;
610 : }
611 :
612 7 : if( osQube[0] == '"' )
613 : {
614 2 : CPLString osTPath = CPLGetPath(GetDescription());
615 2 : CPLString osFilename = osQube;
616 2 : CleanString( osFilename );
617 2 : osTargetFile = CPLFormCIFilename( osTPath, osFilename, NULL );
618 : }
619 :
620 7 : GDALDataType eDataType = GDT_Byte;
621 :
622 :
623 : //image parameters
624 7 : int nRows, nCols, nBands = 1;
625 7 : int nSkipBytes = 0;
626 : int itype;
627 : int record_bytes;
628 7 : int bNoDataSet = FALSE;
629 7 : char chByteOrder = 'M'; //default to MSB
630 7 : double dfNoData = 0.0;
631 :
632 : /* -------------------------------------------------------------------- */
633 : /* Checks to see if this is raw PDS image not compressed image */
634 : /* so ENCODING_TYPE either does not exist or it equals "N/A". */
635 : /* Compressed types will not be supported in this routine */
636 : /* -------------------------------------------------------------------- */
637 : const char *value;
638 :
639 7 : CPLString osEncodingType = GetKeyword( "IMAGE.ENCODING_TYPE", "N/A" );
640 7 : CleanString(osEncodingType);
641 7 : if ( !EQUAL(osEncodingType.c_str(),"N/A") )
642 : {
643 : CPLError( CE_Failure, CPLE_OpenFailed,
644 : "*** PDS image file has an ENCODING_TYPE parameter:\n"
645 : "*** gdal pds driver does not support compressed image types\n"
646 0 : "found: (%s)\n\n", osEncodingType.c_str() );
647 0 : return FALSE;
648 : }
649 : /**************** end ENCODING_TYPE check ***********************/
650 :
651 :
652 : /*********** Grab layout type (BSQ, BIP, BIL) ************/
653 : // AXIS_NAME = (SAMPLE,LINE,BAND)
654 : /*********** Grab samples lines band **************/
655 : /** if AXIS_NAME = "" then Bands=1 and Sample and Lines **/
656 : /** are there own keywords "LINES" and "LINE_SAMPLES" **/
657 : /** if not NULL then CORE_ITEMS keyword i.e. (234,322,2) **/
658 : /***********************************************************/
659 7 : char szLayout[10] = "BSQ"; //default to band seq.
660 7 : value = GetKeyword( "IMAGE.AXIS_NAME", "" );
661 7 : if (EQUAL(value,"(SAMPLE,LINE,BAND)") ) {
662 0 : strcpy(szLayout,"BSQ");
663 0 : nCols = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",1));
664 0 : nRows = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",2));
665 0 : nBands = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",3));
666 : }
667 7 : else if (EQUAL(value,"(BAND,LINE,SAMPLE)") ) {
668 0 : strcpy(szLayout,"BIP");
669 0 : nBands = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",1));
670 0 : nRows = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",2));
671 0 : nCols = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",3));
672 : }
673 7 : else if (EQUAL(value,"(SAMPLE,BAND,LINE)") ) {
674 0 : strcpy(szLayout,"BIL");
675 0 : nCols = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",1));
676 0 : nBands = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",2));
677 0 : nRows = atoi(GetKeywordSub("IMAGE.CORE_ITEMS",3));
678 : }
679 7 : else if ( EQUAL(value,"") ) {
680 7 : strcpy(szLayout,"BSQ");
681 7 : nCols = atoi(GetKeyword("IMAGE.LINE_SAMPLES",""));
682 7 : nRows = atoi(GetKeyword("IMAGE.LINES",""));
683 7 : nBands = atoi(GetKeyword("IMAGE.BANDS","1"));
684 : }
685 : else {
686 : CPLError( CE_Failure, CPLE_OpenFailed,
687 0 : "%s layout not supported. Abort\n\n", value);
688 0 : return FALSE;
689 : }
690 :
691 : /*********** Grab Qube record bytes **********/
692 7 : record_bytes = atoi(GetKeyword("IMAGE.RECORD_BYTES"));
693 7 : if (record_bytes == 0)
694 7 : record_bytes = atoi(GetKeyword("RECORD_BYTES"));
695 :
696 : // this can happen with "record_type = undefined".
697 7 : if( record_bytes == 0 )
698 0 : record_bytes = 1;
699 :
700 7 : if( nQube >0 && osQube.find("<BYTES>") != CPLString::npos )
701 0 : nSkipBytes = nQube - 1;
702 7 : else if (nQube > 0 )
703 5 : nSkipBytes = (nQube - 1) * record_bytes;
704 2 : else if( nDetachedOffset > 0 )
705 : {
706 1 : if (bDetachedOffsetInBytes)
707 1 : nSkipBytes = nDetachedOffset;
708 : else
709 0 : nSkipBytes = nDetachedOffset * record_bytes;
710 : }
711 : else
712 1 : nSkipBytes = 0;
713 :
714 7 : nSkipBytes += atoi(GetKeyword("IMAGE.LINE_PREFIX_BYTES",""));
715 :
716 : /*********** Grab SAMPLE_TYPE *****************/
717 : /** if keyword not found leave as "M" or "MSB" **/
718 7 : CPLString osST = GetKeyword( "IMAGE.SAMPLE_TYPE" );
719 7 : if( osST.size() >= 2 && osST[0] == '"' && osST[osST.size()-1] == '"' )
720 0 : osST = osST.substr( 1, osST.size() - 2 );
721 :
722 7 : if( (EQUAL(osST,"LSB_INTEGER")) ||
723 : (EQUAL(osST,"LSB")) || // just incase
724 : (EQUAL(osST,"LSB_UNSIGNED_INTEGER")) ||
725 : (EQUAL(osST,"LSB_SIGNED_INTEGER")) ||
726 : (EQUAL(osST,"UNSIGNED_INTEGER")) ||
727 : (EQUAL(osST,"VAX_REAL")) ||
728 : (EQUAL(osST,"VAX_INTEGER")) ||
729 : (EQUAL(osST,"PC_INTEGER")) || //just incase
730 : (EQUAL(osST,"PC_REAL")) ) {
731 5 : chByteOrder = 'I';
732 : }
733 :
734 : /**** Grab format type - pds supports 1,2,4,8,16,32,64 (in theory) **/
735 : /**** I have only seen 8, 16, 32 (float) in released datasets **/
736 7 : itype = atoi(GetKeyword("IMAGE.SAMPLE_BITS",""));
737 7 : switch(itype) {
738 : case 8 :
739 5 : eDataType = GDT_Byte;
740 5 : dfNoData = NULL1;
741 5 : bNoDataSet = TRUE;
742 5 : break;
743 : case 16 :
744 2 : if( strstr(osST,"UNSIGNED") != NULL )
745 2 : eDataType = GDT_UInt16;
746 : else
747 0 : eDataType = GDT_Int16;
748 2 : dfNoData = NULL2;
749 2 : bNoDataSet = TRUE;
750 2 : break;
751 : case 32 :
752 0 : eDataType = GDT_Float32;
753 0 : dfNoData = NULL3;
754 0 : bNoDataSet = TRUE;
755 0 : break;
756 : case 64 :
757 0 : eDataType = GDT_Float64;
758 0 : dfNoData = NULL3;
759 0 : bNoDataSet = TRUE;
760 0 : break;
761 : default :
762 : CPLError( CE_Failure, CPLE_AppDefined,
763 : "Sample_bits of %d is not supported in this gdal PDS reader.",
764 0 : itype);
765 0 : return FALSE;
766 : }
767 :
768 : /* -------------------------------------------------------------------- */
769 : /* Did we get the required keywords? If not we return with */
770 : /* this never having been considered to be a match. This isn't */
771 : /* an error! */
772 : /* -------------------------------------------------------------------- */
773 7 : if( nRows < 1 || nCols < 1 || nBands < 1 )
774 : {
775 : CPLError( CE_Failure, CPLE_AppDefined,
776 : "File %s appears to be a PDS file, but failed to find some required keywords.",
777 0 : GetDescription() );
778 0 : return FALSE;
779 : }
780 :
781 : /* -------------------------------------------------------------------- */
782 : /* Capture some information from the file that is of interest. */
783 : /* -------------------------------------------------------------------- */
784 7 : nRasterXSize = nCols;
785 7 : nRasterYSize = nRows;
786 :
787 : /* -------------------------------------------------------------------- */
788 : /* Open target binary file. */
789 : /* -------------------------------------------------------------------- */
790 :
791 7 : if( eAccess == GA_ReadOnly )
792 : {
793 7 : fpImage = VSIFOpenL( osTargetFile, "rb" );
794 7 : if( fpImage == NULL )
795 : {
796 : CPLError( CE_Failure, CPLE_OpenFailed,
797 : "Failed to open %s.\n%s",
798 : osTargetFile.c_str(),
799 0 : VSIStrerror( errno ) );
800 0 : return FALSE;
801 : }
802 : }
803 : else
804 : {
805 0 : fpImage = VSIFOpenL( osTargetFile, "r+b" );
806 0 : if( fpImage == NULL )
807 : {
808 : CPLError( CE_Failure, CPLE_OpenFailed,
809 : "Failed to open %s with write permission.\n%s",
810 : osTargetFile.c_str(),
811 0 : VSIStrerror( errno ) );
812 0 : return FALSE;
813 : }
814 : }
815 :
816 : /* -------------------------------------------------------------------- */
817 : /* Compute the line offset. */
818 : /* -------------------------------------------------------------------- */
819 7 : int nItemSize = GDALGetDataTypeSize(eDataType)/8;
820 7 : int nLineOffset = record_bytes;
821 : int nPixelOffset, nBandOffset;
822 :
823 7 : if( EQUAL(szLayout,"BIP") )
824 : {
825 0 : nPixelOffset = nItemSize * nBands;
826 0 : nBandOffset = nItemSize;
827 : nLineOffset = ((nPixelOffset * nCols + record_bytes - 1)/record_bytes)
828 0 : * record_bytes;
829 : }
830 7 : else if( EQUAL(szLayout,"BSQ") )
831 : {
832 7 : nPixelOffset = nItemSize;
833 7 : nBandOffset = nLineOffset * nRows;
834 : nLineOffset = ((nPixelOffset * nCols + record_bytes - 1)/record_bytes)
835 7 : * record_bytes;
836 : }
837 : else /* assume BIL */
838 : {
839 0 : nPixelOffset = nItemSize;
840 0 : nBandOffset = nItemSize * nCols;
841 : nLineOffset = ((nBandOffset * nCols + record_bytes - 1)/record_bytes)
842 0 : * record_bytes;
843 : }
844 :
845 : /* -------------------------------------------------------------------- */
846 : /* Create band information objects. */
847 : /* -------------------------------------------------------------------- */
848 : int i;
849 :
850 7 : nBands = nBands;;
851 14 : for( i = 0; i < nBands; i++ )
852 : {
853 : RawRasterBand *poBand;
854 :
855 : poBand =
856 : new RawRasterBand( this, i+1, fpImage,
857 : nSkipBytes + nBandOffset * i,
858 : nPixelOffset, nLineOffset, eDataType,
859 : #ifdef CPL_LSB
860 : chByteOrder == 'I' || chByteOrder == 'L',
861 : #else
862 : chByteOrder == 'M',
863 : #endif
864 7 : TRUE );
865 :
866 7 : if( nBands == 1 )
867 : {
868 7 : const char* pszMin = GetKeyword("IMAGE.MINIMUM", NULL);
869 7 : const char* pszMax = GetKeyword("IMAGE.MAXIMUM", NULL);
870 7 : const char* pszMean = GetKeyword("IMAGE.MEAN", NULL);
871 7 : const char* pszStdDev= GetKeyword("IMAGE.STANDARD_DEVIATION", NULL);
872 7 : if (pszMin != NULL && pszMax != NULL &&
873 : pszMean != NULL && pszStdDev != NULL)
874 : {
875 : poBand->SetStatistics( CPLAtofM(pszMin),
876 : CPLAtofM(pszMax),
877 : CPLAtofM(pszMean),
878 0 : CPLAtofM(pszStdDev));
879 : }
880 : }
881 :
882 7 : if( bNoDataSet )
883 7 : poBand->SetNoDataValue( dfNoData );
884 :
885 7 : SetBand( i+1, poBand );
886 :
887 : // Set offset/scale values at the PAM level.
888 : poBand->SetOffset(
889 7 : CPLAtofM(GetKeyword("IMAGE.OFFSET","0.0")));
890 : poBand->SetScale(
891 7 : CPLAtofM(GetKeyword("IMAGE.SCALING_FACTOR","1.0")));
892 : }
893 :
894 7 : return TRUE;
895 : }
896 :
897 : /************************************************************************/
898 : /* ==================================================================== */
899 : /* PDSWrapperRasterBand */
900 : /* */
901 : /* proxy for the jp2 or other compressed bands. */
902 : /* ==================================================================== */
903 : /************************************************************************/
904 : class PDSWrapperRasterBand : public GDALProxyRasterBand
905 : {
906 : GDALRasterBand* poBaseBand;
907 :
908 : protected:
909 22 : virtual GDALRasterBand* RefUnderlyingRasterBand() { return poBaseBand; }
910 :
911 : public:
912 2 : PDSWrapperRasterBand( GDALRasterBand* poBaseBand )
913 2 : {
914 2 : this->poBaseBand = poBaseBand;
915 2 : eDataType = poBaseBand->GetRasterDataType();
916 2 : poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
917 2 : }
918 2 : ~PDSWrapperRasterBand() {}
919 : };
920 :
921 : /************************************************************************/
922 : /* ParseCompressedImage() */
923 : /************************************************************************/
924 :
925 2 : int PDSDataset::ParseCompressedImage()
926 :
927 : {
928 2 : CPLString osFileName = GetKeyword( "COMPRESSED_FILE.FILE_NAME", "" );
929 2 : CleanString( osFileName );
930 :
931 2 : CPLString osPath = CPLGetPath(GetDescription());
932 2 : CPLString osFullFileName = CPLFormFilename( osPath, osFileName, NULL );
933 : int iBand;
934 :
935 2 : poCompressedDS = (GDALDataset*) GDALOpen( osFullFileName, GA_ReadOnly );
936 :
937 2 : if( poCompressedDS == NULL )
938 0 : return FALSE;
939 :
940 2 : nRasterXSize = poCompressedDS->GetRasterXSize();
941 2 : nRasterYSize = poCompressedDS->GetRasterYSize();
942 :
943 4 : for( iBand = 0; iBand < poCompressedDS->GetRasterCount(); iBand++ )
944 : {
945 2 : SetBand( iBand+1, new PDSWrapperRasterBand( poCompressedDS->GetRasterBand( iBand+1 ) ) );
946 : }
947 :
948 2 : return TRUE;
949 : }
950 :
951 : /************************************************************************/
952 : /* Identify() */
953 : /************************************************************************/
954 :
955 10296 : int PDSDataset::Identify( GDALOpenInfo * poOpenInfo )
956 :
957 : {
958 10296 : if( poOpenInfo->pabyHeader == NULL )
959 9286 : return FALSE;
960 :
961 1010 : return strstr((char*)poOpenInfo->pabyHeader,"PDS_VERSION_ID") != NULL;
962 : }
963 :
964 : /************************************************************************/
965 : /* Open() */
966 : /************************************************************************/
967 :
968 2051 : GDALDataset *PDSDataset::Open( GDALOpenInfo * poOpenInfo )
969 : {
970 2051 : if( !Identify( poOpenInfo ) )
971 2042 : return NULL;
972 :
973 9 : if( strstr((const char *)poOpenInfo->pabyHeader,"PDS3") == NULL )
974 : {
975 : CPLError( CE_Failure, CPLE_OpenFailed,
976 0 : "It appears this is an older PDS image type. Only PDS_VERSION_ID = PDS3 are currently supported by this gdal PDS reader.");
977 0 : return NULL;
978 : }
979 :
980 : /* -------------------------------------------------------------------- */
981 : /* Open and parse the keyword header. Sometimes there is stuff */
982 : /* before the PDS_VERSION_ID, which we want to ignore. */
983 : /* -------------------------------------------------------------------- */
984 9 : FILE *fpQube = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
985 :
986 9 : if( fpQube == NULL )
987 0 : return NULL;
988 :
989 : PDSDataset *poDS;
990 :
991 9 : poDS = new PDSDataset();
992 9 : poDS->SetDescription( poOpenInfo->pszFilename );
993 9 : poDS->eAccess = poOpenInfo->eAccess;
994 :
995 9 : const char* pszPDSVersionID = strstr((const char *)poOpenInfo->pabyHeader,"PDS_VERSION_ID");
996 9 : int nOffset = 0;
997 9 : if (pszPDSVersionID)
998 9 : nOffset = pszPDSVersionID - (const char *)poOpenInfo->pabyHeader;
999 :
1000 9 : if( ! poDS->oKeywords.Ingest( fpQube, nOffset ) )
1001 : {
1002 0 : delete poDS;
1003 0 : VSIFCloseL( fpQube );
1004 0 : return NULL;
1005 : }
1006 9 : VSIFCloseL( fpQube );
1007 :
1008 : /* -------------------------------------------------------------------- */
1009 : /* Is this a comprssed image with COMPRESSED_FILE subdomain? */
1010 : /* */
1011 : /* The corresponding parse operations will read keywords, */
1012 : /* establish bands and raster size. */
1013 : /* -------------------------------------------------------------------- */
1014 9 : CPLString osEncodingType = poDS->GetKeyword( "COMPRESSED_FILE.ENCODING_TYPE", "" );
1015 :
1016 9 : if( osEncodingType.size() != 0 )
1017 : {
1018 2 : if( !poDS->ParseCompressedImage() )
1019 : {
1020 0 : delete poDS;
1021 9 : return NULL;
1022 : }
1023 : }
1024 : else
1025 : {
1026 7 : if( !poDS->ParseUncompressedImage() )
1027 : {
1028 0 : delete poDS;
1029 0 : return NULL;
1030 : }
1031 : }
1032 :
1033 : /* -------------------------------------------------------------------- */
1034 : /* Set the coordinate system and geotransform. */
1035 : /* -------------------------------------------------------------------- */
1036 9 : poDS->ParseSRS();
1037 :
1038 : /* -------------------------------------------------------------------- */
1039 : /* Transfer a few interesting keywords as metadata. */
1040 : /* -------------------------------------------------------------------- */
1041 : int i;
1042 : static const char *apszKeywords[] =
1043 : { "FILTER_NAME", "DATA_SET_ID", "PRODUCT_ID",
1044 : "PRODUCER_INSTITUTION_NAME", "PRODUCT_TYPE", "MISSION_NAME",
1045 : "SPACECRAFT_NAME", "INSTRUMENT_NAME", "INSTRUMENT_ID",
1046 : "TARGET_NAME", "CENTER_FILTER_WAVELENGTH", "BANDWIDTH",
1047 : "PRODUCT_CREATION_TIME", "NOTE",
1048 : NULL };
1049 :
1050 135 : for( i = 0; apszKeywords[i] != NULL; i++ )
1051 : {
1052 126 : const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
1053 :
1054 126 : if( pszKeywordValue != NULL )
1055 126 : poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
1056 : }
1057 :
1058 : /* -------------------------------------------------------------------- */
1059 : /* Initialize any PAM information. */
1060 : /* -------------------------------------------------------------------- */
1061 9 : poDS->TryLoadXML();
1062 :
1063 : /* -------------------------------------------------------------------- */
1064 : /* Check for overviews. */
1065 : /* -------------------------------------------------------------------- */
1066 9 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1067 :
1068 9 : return( poDS );
1069 : }
1070 :
1071 : /************************************************************************/
1072 : /* GetKeyword() */
1073 : /************************************************************************/
1074 :
1075 : const char *PDSDataset::GetKeyword( const char *pszPath,
1076 364 : const char *pszDefault )
1077 :
1078 : {
1079 364 : return oKeywords.GetKeyword( pszPath, pszDefault );
1080 : }
1081 :
1082 : /************************************************************************/
1083 : /* GetKeywordSub() */
1084 : /************************************************************************/
1085 :
1086 : const char *PDSDataset::GetKeywordSub( const char *pszPath,
1087 : int iSubscript,
1088 6 : const char *pszDefault )
1089 :
1090 : {
1091 6 : const char *pszResult = oKeywords.GetKeyword( pszPath, NULL );
1092 :
1093 6 : if( pszResult == NULL )
1094 0 : return pszDefault;
1095 :
1096 6 : if( pszResult[0] != '(' )
1097 0 : return pszDefault;
1098 :
1099 : char **papszTokens = CSLTokenizeString2( pszResult, "(,)",
1100 6 : CSLT_HONOURSTRINGS );
1101 :
1102 6 : if( iSubscript <= CSLCount(papszTokens) )
1103 : {
1104 6 : osTempResult = papszTokens[iSubscript-1];
1105 6 : CSLDestroy( papszTokens );
1106 6 : return osTempResult.c_str();
1107 : }
1108 : else
1109 : {
1110 0 : CSLDestroy( papszTokens );
1111 0 : return pszDefault;
1112 : }
1113 : }
1114 :
1115 : /************************************************************************/
1116 : /* GetKeywordUnit() */
1117 : /************************************************************************/
1118 :
1119 : const char *PDSDataset::GetKeywordUnit( const char *pszPath,
1120 : int iSubscript,
1121 7 : const char *pszDefault )
1122 :
1123 : {
1124 7 : const char *pszResult = oKeywords.GetKeyword( pszPath, NULL );
1125 :
1126 7 : if( pszResult == NULL )
1127 0 : return pszDefault;
1128 :
1129 : char **papszTokens = CSLTokenizeString2( pszResult, "</>",
1130 7 : CSLT_HONOURSTRINGS );
1131 :
1132 7 : if( iSubscript <= CSLCount(papszTokens) )
1133 : {
1134 6 : osTempResult = papszTokens[iSubscript-1];
1135 6 : CSLDestroy( papszTokens );
1136 6 : return osTempResult.c_str();
1137 : }
1138 : else
1139 : {
1140 1 : CSLDestroy( papszTokens );
1141 1 : return pszDefault;
1142 : }
1143 : }
1144 :
1145 : /************************************************************************/
1146 : /* CleanString() */
1147 : /* */
1148 : /* Removes single or double quotes, and converts spaces to underscores. */
1149 : /* The change is made in-place to CPLString. */
1150 : /************************************************************************/
1151 :
1152 29 : void PDSDataset::CleanString( CPLString &osInput )
1153 :
1154 : {
1155 29 : if( ( osInput.size() < 2 ) ||
1156 : ((osInput.at(0) != '"' || osInput.at(osInput.size()-1) != '"' ) &&
1157 : ( osInput.at(0) != '\'' || osInput.at(osInput.size()-1) != '\'')) )
1158 14 : return;
1159 :
1160 15 : char *pszWrk = CPLStrdup(osInput.c_str() + 1);
1161 : int i;
1162 :
1163 15 : pszWrk[strlen(pszWrk)-1] = '\0';
1164 :
1165 145 : for( i = 0; pszWrk[i] != '\0'; i++ )
1166 : {
1167 130 : if( pszWrk[i] == ' ' )
1168 2 : pszWrk[i] = '_';
1169 : }
1170 :
1171 15 : osInput = pszWrk;
1172 15 : CPLFree( pszWrk );
1173 : }
1174 : /************************************************************************/
1175 : /* GDALRegister_PDS() */
1176 : /************************************************************************/
1177 :
1178 409 : void GDALRegister_PDS()
1179 :
1180 : {
1181 : GDALDriver *poDriver;
1182 :
1183 409 : if( GDALGetDriverByName( "PDS" ) == NULL )
1184 : {
1185 392 : poDriver = new GDALDriver();
1186 :
1187 392 : poDriver->SetDescription( "PDS" );
1188 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1189 392 : "NASA Planetary Data System" );
1190 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1191 392 : "frmt_various.html#PDS" );
1192 :
1193 392 : poDriver->pfnOpen = PDSDataset::Open;
1194 392 : poDriver->pfnIdentify = PDSDataset::Identify;
1195 :
1196 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
1197 : }
1198 409 : }
1199 :
|