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