LCOV - code coverage report
Current view: directory - frmts/pds - pdsdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 450 353 78.4 %
Date: 2012-12-26 Functions: 25 19 76.0 %

       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                 : 

Generated by: LCOV version 1.7