LCOV - code coverage report
Current view: directory - frmts/raw - fastdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 529 392 74.1 %
Date: 2012-12-26 Functions: 20 14 70.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: fastdataset.cpp 22610 2011-06-28 21:20:06Z rouault $
       3                 :  *
       4                 :  * Project:  EOSAT FAST Format reader
       5                 :  * Purpose:  Reads Landsat FAST-L7A, IRS 1C/1D
       6                 :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "cpl_string.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "ogr_spatialref.h"
      33                 : #include "rawdataset.h"
      34                 : 
      35                 : CPL_CVSID("$Id: fastdataset.cpp 22610 2011-06-28 21:20:06Z rouault $");
      36                 : 
      37                 : CPL_C_START
      38                 : void  GDALRegister_FAST(void);
      39                 : CPL_C_END
      40                 : 
      41                 : #define ADM_STD_HEADER_SIZE 4608    // XXX: Format specification says it
      42                 : #define ADM_HEADER_SIZE   5000    // should be 4608, but some vendors
      43                 :                                         // ship broken large datasets.
      44                 : #define ADM_MIN_HEADER_SIZE     1536    // ...and sometimes it can be
      45                 :                                         // even 1/3 of standard size
      46                 : 
      47                 : #define ACQUISITION_DATE        "ACQUISITION DATE"
      48                 : #define ACQUISITION_DATE_SIZE   8
      49                 : 
      50                 : #define SATELLITE_NAME          "SATELLITE"
      51                 : #define SATELLITE_NAME_SIZE     10
      52                 : 
      53                 : #define SENSOR_NAME             "SENSOR"
      54                 : #define SENSOR_NAME_SIZE        10
      55                 : 
      56                 : #define BANDS_PRESENT           "BANDS PRESENT"
      57                 : #define BANDS_PRESENT_SIZE      32
      58                 : 
      59                 : #define FILENAME                "FILENAME"
      60                 : #define FILENAME_SIZE           29
      61                 : 
      62                 : #define PIXELS                  "PIXELS PER LINE"
      63                 : #define PIXELS_SIZE             5
      64                 : 
      65                 : #define LINES1                  "LINES PER BAND"
      66                 : #define LINES2                  "LINES PER IMAGE"
      67                 : #define LINES_SIZE              5
      68                 : 
      69                 : #define BITS_PER_PIXEL          "OUTPUT BITS PER PIXEL"
      70                 : #define BITS_PER_PIXEL_SIZE     2
      71                 : 
      72                 : #define PROJECTION_NAME         "MAP PROJECTION"
      73                 : #define PROJECTION_NAME_SIZE    4
      74                 : 
      75                 : #define ELLIPSOID_NAME          "ELLIPSOID"
      76                 : #define ELLIPSOID_NAME_SIZE     18
      77                 : 
      78                 : #define DATUM_NAME              "DATUM"
      79                 : #define DATUM_NAME_SIZE         6
      80                 : 
      81                 : #define ZONE_NUMBER             "USGS MAP ZONE"
      82                 : #define ZONE_NUMBER_SIZE        6
      83                 : 
      84                 : #define USGS_PARAMETERS         "USGS PROJECTION PARAMETERS"
      85                 : 
      86                 : #define CORNER_UPPER_LEFT       "UL "
      87                 : #define CORNER_UPPER_RIGHT      "UR "
      88                 : #define CORNER_LOWER_LEFT       "LL "
      89                 : #define CORNER_LOWER_RIGHT      "LR "
      90                 : #define CORNER_VALUE_SIZE       13
      91                 : 
      92                 : #define VALUE_SIZE              24
      93                 : 
      94                 : enum FASTSatellite  // Satellites:
      95                 : {
      96                 :     LANDSAT,      // Landsat 7
      97                 :     IRS       // IRS 1C/1D
      98                 : };
      99                 : 
     100                 : /************************************************************************/
     101                 : /* ==================================================================== */
     102                 : /*        FASTDataset       */
     103                 : /* ==================================================================== */
     104                 : /************************************************************************/
     105                 : 
     106                 : class FASTDataset : public GDALPamDataset
     107                 : {
     108                 :     friend class FASTRasterBand;
     109                 : 
     110                 :     double      adfGeoTransform[6];
     111                 :     char        *pszProjection;
     112                 : 
     113                 :     VSILFILE  *fpHeader;
     114                 :     CPLString apoChannelFilenames[7];
     115                 :     VSILFILE  *fpChannels[7];
     116                 :     const char  *pszFilename;
     117                 :     char  *pszDirname;
     118                 :     GDALDataType eDataType;
     119                 :     FASTSatellite iSatellite;
     120                 :     
     121                 :     int         OpenChannel( const char *pszFilename, int iBand );
     122                 : 
     123                 :   public:
     124                 :                 FASTDataset();
     125                 :     ~FASTDataset();
     126                 :     
     127                 :     static GDALDataset *Open( GDALOpenInfo * );
     128                 : 
     129                 :     CPLErr  GetGeoTransform( double * );
     130                 :     const char  *GetProjectionRef();
     131                 :     VSILFILE  *FOpenChannel( const char *, int iBand, int iFASTBand );
     132                 :     void        TryEuromap_IRS_1C_1D_ChannelNameConvention();
     133                 :     
     134                 :     virtual  char** GetFileList();
     135                 : };
     136                 : 
     137                 : /************************************************************************/
     138                 : /* ==================================================================== */
     139                 : /*                            FASTRasterBand                            */
     140                 : /* ==================================================================== */
     141                 : /************************************************************************/
     142                 : 
     143                 : class FASTRasterBand : public RawRasterBand
     144              18 : {
     145                 :     friend class FASTDataset;
     146                 : 
     147                 :   public:
     148                 : 
     149                 :         FASTRasterBand( FASTDataset *, int, VSILFILE *, vsi_l_offset,
     150                 :         int, int, GDALDataType, int );
     151                 : };
     152                 : 
     153                 : 
     154                 : /************************************************************************/
     155                 : /*                           FASTRasterBand()                           */
     156                 : /************************************************************************/
     157                 : 
     158              18 : FASTRasterBand::FASTRasterBand( FASTDataset *poDS, int nBand, VSILFILE * fpRaw,
     159                 :                                 vsi_l_offset nImgOffset, int nPixelOffset,
     160                 :                                 int nLineOffset, GDALDataType eDataType,
     161                 :         int bNativeOrder) :
     162                 :                  RawRasterBand( poDS, nBand, fpRaw, nImgOffset, nPixelOffset,
     163              18 :                                nLineOffset, eDataType, bNativeOrder, TRUE)
     164                 : {
     165                 : 
     166              18 : }
     167                 : 
     168                 : /************************************************************************/
     169                 : /* ==================================================================== */
     170                 : /*        FASTDataset       */
     171                 : /* ==================================================================== */
     172                 : /************************************************************************/
     173                 : 
     174                 : /************************************************************************/
     175                 : /*                           FASTDataset()                              */
     176                 : /************************************************************************/
     177                 : 
     178               7 : FASTDataset::FASTDataset()
     179                 : 
     180                 : {
     181               7 :     fpHeader = NULL;
     182               7 :     pszDirname = NULL;
     183              14 :     pszProjection = CPLStrdup( "" );
     184               7 :     adfGeoTransform[0] = 0.0;
     185               7 :     adfGeoTransform[1] = 1.0;
     186               7 :     adfGeoTransform[2] = 0.0;
     187               7 :     adfGeoTransform[3] = 0.0;
     188               7 :     adfGeoTransform[4] = 0.0;
     189               7 :     adfGeoTransform[5] = 1.0;
     190               7 :     nBands = 0;
     191               7 : }
     192                 : 
     193                 : /************************************************************************/
     194                 : /*                            ~FASTDataset()                            */
     195                 : /************************************************************************/
     196                 : 
     197               7 : FASTDataset::~FASTDataset()
     198                 : 
     199                 : {
     200                 :     int i;
     201                 : 
     202               7 :     FlushCache();
     203                 : 
     204               7 :     if ( pszDirname )
     205               7 :   CPLFree( pszDirname );
     206               7 :     if ( pszProjection )
     207               7 :   CPLFree( pszProjection );
     208              25 :     for ( i = 0; i < nBands; i++ )
     209              18 :   if ( fpChannels[i] )
     210              18 :       VSIFCloseL( fpChannels[i] );
     211               7 :     if( fpHeader != NULL )
     212               7 :         VSIFCloseL( fpHeader );
     213               7 : }
     214                 : 
     215                 : /************************************************************************/
     216                 : /*                          GetGeoTransform()                           */
     217                 : /************************************************************************/
     218                 : 
     219               5 : CPLErr FASTDataset::GetGeoTransform( double * padfTransform )
     220                 : 
     221                 : {
     222               5 :     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
     223               5 :     return CE_None;
     224                 : }
     225                 : 
     226                 : /************************************************************************/
     227                 : /*                          GetProjectionRef()                          */
     228                 : /************************************************************************/
     229                 : 
     230               4 : const char *FASTDataset::GetProjectionRef()
     231                 : 
     232                 : {
     233               4 :     if( pszProjection )
     234               4 :         return pszProjection;
     235                 :     else
     236               0 :         return "";
     237                 : }
     238                 : 
     239                 : /************************************************************************/
     240                 : /*                             GetFileList()                            */
     241                 : /************************************************************************/
     242                 : 
     243               0 : char** FASTDataset::GetFileList()
     244                 : {
     245               0 :     char** papszFileList = GDALPamDataset::GetFileList();
     246                 :     int i;
     247               0 :     for(i=0;i<6;i++)
     248                 :     {
     249               0 :         if (apoChannelFilenames[i].size() > 0)
     250                 :             papszFileList =
     251               0 :                 CSLAddString(papszFileList, apoChannelFilenames[i].c_str());
     252                 :     }
     253                 :     
     254               0 :     return papszFileList;
     255                 : }
     256                 : 
     257                 : /************************************************************************/
     258                 : /*                             OpenChannel()                            */
     259                 : /************************************************************************/
     260                 : 
     261              67 : int FASTDataset::OpenChannel( const char *pszFilename, int iBand )
     262                 : {
     263              67 :     fpChannels[iBand] = VSIFOpenL( pszFilename, "rb" );
     264              67 :     if (fpChannels[iBand])
     265              18 :         apoChannelFilenames[iBand] = pszFilename;
     266              67 :     return fpChannels[iBand] != NULL;
     267                 : }
     268                 : 
     269                 : /************************************************************************/
     270                 : /*                             FOpenChannel()                           */
     271                 : /************************************************************************/
     272                 : 
     273                 : 
     274              28 : VSILFILE *FASTDataset::FOpenChannel( const char *pszBandname, int iBand, int iFASTBand )
     275                 : {
     276              28 :     const char  *pszChannelFilename = NULL;
     277              28 :     char  *pszPrefix = CPLStrdup( CPLGetBasename( pszFilename ) );
     278              28 :     char  *pszSuffix = CPLStrdup( CPLGetExtension( pszFilename ) );
     279                 : 
     280              28 :     fpChannels[iBand] = NULL;
     281                 :     
     282              28 :     switch ( iSatellite )
     283                 :     {
     284                 :   case LANDSAT:
     285              21 :             if ( pszBandname && !EQUAL( pszBandname, "" ) )
     286                 :             {
     287                 :                 pszChannelFilename =
     288               4 :                     CPLFormCIFilename( pszDirname, pszBandname, NULL );
     289               4 :                 if ( OpenChannel( pszChannelFilename, iBand ) )
     290               4 :                     break;
     291                 :                 pszChannelFilename =
     292                 :                     CPLFormFilename( pszDirname,
     293                 :                             CPLSPrintf( "%s.b%02d", pszPrefix, iFASTBand ),
     294               0 :                             NULL );
     295               0 :                 OpenChannel( pszChannelFilename, iBand );
     296                 :             }
     297              17 :             break;
     298                 :   case IRS:
     299                 :   default:
     300                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     301               7 :                 CPLSPrintf( "%s.%d", pszPrefix, iFASTBand ), pszSuffix );
     302               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     303               0 :                 break;
     304                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     305               7 :                 CPLSPrintf( "IMAGERY%d", iFASTBand ), pszSuffix );
     306               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     307               0 :                 break;
     308                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     309               7 :                 CPLSPrintf( "imagery%d", iFASTBand ), pszSuffix );
     310               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     311               0 :                 break;
     312                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     313               7 :                 CPLSPrintf( "IMAGERY%d.DAT", iFASTBand ), NULL );
     314               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     315               0 :                 break;
     316                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     317               7 :                 CPLSPrintf( "imagery%d.dat", iFASTBand ), NULL );
     318               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     319               0 :                 break;
     320                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     321               7 :                 CPLSPrintf( "IMAGERY%d.dat", iFASTBand ), NULL );
     322               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     323               0 :                 break;
     324                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     325               7 :                 CPLSPrintf( "imagery%d.DAT", iFASTBand ), NULL );
     326               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     327               0 :                 break;
     328                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     329               7 :                 CPLSPrintf( "BAND%d", iFASTBand ), pszSuffix );
     330               7 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     331               7 :                 break;
     332                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     333               0 :                 CPLSPrintf( "band%d", iFASTBand ), pszSuffix );
     334               0 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     335               0 :                 break;
     336                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     337               0 :                 CPLSPrintf( "BAND%d.DAT", iFASTBand ), NULL );
     338               0 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     339               0 :                 break;
     340                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     341               0 :                 CPLSPrintf( "band%d.dat", iFASTBand ), NULL );
     342               0 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     343               0 :                 break;
     344                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     345               0 :                 CPLSPrintf( "BAND%d.dat", iFASTBand ), NULL );
     346               0 :             if ( OpenChannel( pszChannelFilename, iBand ) )
     347               0 :                 break;
     348                 :             pszChannelFilename = CPLFormFilename( pszDirname,
     349               0 :                 CPLSPrintf( "band%d.DAT", iFASTBand ), NULL );
     350               0 :             OpenChannel( pszChannelFilename, iBand );
     351                 :             break;
     352                 :     }
     353                 :     
     354              28 :     CPLDebug( "FAST", "Band %d filename=%s", iBand + 1, pszChannelFilename);
     355                 : 
     356              28 :     CPLFree( pszPrefix );
     357              28 :     CPLFree( pszSuffix );
     358              28 :     return fpChannels[iBand];
     359                 : }
     360                 : 
     361                 : /************************************************************************/
     362                 : /*                TryEuromap_IRS_1C_1D_ChannelNameConvention()                     */
     363                 : /************************************************************************/
     364                 : 
     365               3 : void FASTDataset::TryEuromap_IRS_1C_1D_ChannelNameConvention()
     366                 : {
     367                 :     /* Filename convention explained in http://www.euromap.de/download/em_names.pdf */
     368                 : 
     369               3 :     char chLastLetterHeader = pszFilename[strlen(pszFilename)-1];
     370               3 :     if (EQUAL(GetMetadataItem("SENSOR"), "PAN"))
     371                 :     {
     372                 :         /* Converting upper-case to lower case */
     373               1 :         if (chLastLetterHeader >= 'A' && chLastLetterHeader <= 'M')
     374               0 :             chLastLetterHeader += 'a' - 'A';
     375                 : 
     376               2 :         if (chLastLetterHeader >= 'a' && chLastLetterHeader <= 'j')
     377                 :         {
     378               1 :             char chLastLetterData = chLastLetterHeader - 'a' + '0';
     379               1 :             char* pszChannelFilename = CPLStrdup(pszFilename);
     380               1 :             pszChannelFilename[strlen(pszChannelFilename)-1] = chLastLetterData;
     381               1 :             if (OpenChannel( pszChannelFilename, 0 ))
     382               1 :                 nBands++;
     383                 :             else
     384               0 :                 CPLDebug("FAST", "Could not find %s", pszChannelFilename);
     385               1 :             CPLFree(pszChannelFilename);
     386                 :         }
     387               0 :         else if (chLastLetterHeader >= 'k' && chLastLetterHeader <= 'm')
     388                 :         {
     389               0 :             char chLastLetterData = chLastLetterHeader - 'k' + 'n';
     390               0 :             char* pszChannelFilename = CPLStrdup(pszFilename);
     391               0 :             pszChannelFilename[strlen(pszChannelFilename)-1] = chLastLetterData;
     392               0 :             if (OpenChannel( pszChannelFilename, 0 ))
     393               0 :                 nBands++;
     394                 :             else
     395                 :             {
     396                 :                 /* Trying upper-case */
     397               0 :                 pszChannelFilename[strlen(pszChannelFilename)-1] = chLastLetterData - 'a' + 'A';
     398               0 :                 if (OpenChannel( pszChannelFilename, 0 ))
     399               0 :                     nBands++;
     400                 :                 else
     401               0 :                     CPLDebug("FAST", "Could not find %s", pszChannelFilename);
     402                 :             }
     403               0 :             CPLFree(pszChannelFilename);
     404                 :         }
     405                 :         else
     406                 :         {
     407               0 :             CPLDebug("FAST", "Unknown last letter (%c) for a IRS PAN Euromap FAST dataset", chLastLetterHeader);
     408                 :         }
     409                 :     }
     410               2 :     else if (EQUAL(GetMetadataItem("SENSOR"), "LISS3"))
     411                 :     {
     412                 :         const char apchLISSFilenames[7][5] = {
     413                 :             { '0', '2', '3', '4', '5' },
     414                 :             { '6', '7', '8', '9', 'a' },
     415                 :             { 'b', 'c', 'd', 'e', 'f' },
     416                 :             { 'g', 'h', 'i', 'j', 'k' },
     417                 :             { 'l', 'm', 'n', 'o', 'p' },
     418                 :             { 'q', 'r', 's', 't', 'u' },
     419               1 :             { 'v', 'w', 'x', 'y', 'z' } };
     420                 :         int i;
     421               5 :         for (i = 0; i < 7 ; i++)
     422                 :         {
     423              15 :             if (chLastLetterHeader == apchLISSFilenames[i][0] ||
     424               6 :                 (apchLISSFilenames[i][0] >= 'a' && apchLISSFilenames[i][0] <= 'z' &&
     425               2 :                     (apchLISSFilenames[i][0] - chLastLetterHeader == 0 ||
     426               2 :                     apchLISSFilenames[i][0] - chLastLetterHeader == 32)))
     427                 :             {
     428               5 :                 for (int j = 0; j < 4; j ++)
     429                 :                 {
     430               4 :                     char* pszChannelFilename = CPLStrdup(pszFilename);
     431               4 :                     pszChannelFilename[strlen(pszChannelFilename)-1] = apchLISSFilenames[i][j+1];
     432               4 :                     if (OpenChannel( pszChannelFilename, nBands ))
     433               4 :                         nBands++;
     434               0 :                     else if (apchLISSFilenames[i][j+1] >= 'a' && apchLISSFilenames[i][j+1] <= 'z')
     435                 :                     {
     436                 :                         /* Trying upper-case */
     437               0 :                         pszChannelFilename[strlen(pszChannelFilename)-1] = apchLISSFilenames[i][j+1] - 'a' + 'A';
     438               0 :                         if (OpenChannel( pszChannelFilename, nBands ))
     439               0 :                             nBands++;
     440                 :                         else
     441                 :                         {
     442               0 :                             CPLDebug("FAST", "Could not find %s", pszChannelFilename);
     443                 :                         }
     444                 :                     }
     445                 :                     else
     446                 :                     {
     447               0 :                         CPLDebug("FAST", "Could not find %s", pszChannelFilename);
     448                 :                     }
     449               4 :                     CPLFree(pszChannelFilename);
     450                 :                 }
     451               1 :                 break;
     452                 :             }
     453                 :         }
     454               1 :         if (i == 7)
     455                 :         {
     456               0 :             CPLDebug("FAST", "Unknown last letter (%c) for a IRS LISS3 Euromap FAST dataset", chLastLetterHeader);
     457                 :         }
     458                 :     }
     459               1 :     else if (EQUAL(GetMetadataItem("SENSOR"), "WIFS"))
     460                 :     {
     461               1 :         if (chLastLetterHeader == '0')
     462                 :         {
     463               3 :             for (int j = 0; j < 2; j ++)
     464                 :             {
     465               2 :                 char* pszChannelFilename = CPLStrdup(pszFilename);
     466               2 :                 pszChannelFilename[strlen(pszChannelFilename)-1] 
     467               2 :                     = (char) ('1' + j);
     468               2 :                 if (OpenChannel( pszChannelFilename, nBands ))
     469               2 :                     nBands++;
     470                 :                 else
     471                 :                 {
     472               0 :                     CPLDebug("FAST", "Could not find %s", pszChannelFilename);
     473                 :                 }
     474               2 :                 CPLFree(pszChannelFilename);
     475                 :             }
     476                 :         }
     477                 :         else
     478                 :         {
     479               0 :             CPLDebug("FAST", "Unknown last letter (%c) for a IRS WIFS Euromap FAST dataset", chLastLetterHeader);
     480                 :         }
     481                 :     }
     482                 :     else
     483                 :     {
     484               0 :         CPLAssert(0);
     485                 :     }
     486               3 : }
     487                 : 
     488                 : /************************************************************************/
     489                 : /*                          GetValue()                                  */
     490                 : /************************************************************************/
     491                 : 
     492              71 : static char *GetValue( const char *pszString, const char *pszName,
     493                 :                        int iValueSize, int bNormalize )
     494                 : {
     495              71 :     char    *pszTemp = strstr( (char *) pszString, pszName );
     496                 : 
     497              71 :     if ( pszTemp )
     498                 :     {
     499                 :         // Skip the parameter name
     500              63 :         pszTemp += strlen( pszName );
     501                 :         // Skip whitespaces and equal signs
     502             187 :         while ( *pszTemp == ' ' )
     503              61 :             pszTemp++;
     504             189 :         while ( *pszTemp == '=' )
     505              63 :             pszTemp++;
     506                 : 
     507              63 :         pszTemp = CPLScanString( pszTemp, iValueSize, TRUE, bNormalize );
     508                 :     }
     509                 : 
     510              71 :     return pszTemp;
     511                 : }
     512                 : 
     513                 : /************************************************************************/
     514                 : /*                        USGSMnemonicToCode()                          */
     515                 : /************************************************************************/
     516                 : 
     517               6 : static long USGSMnemonicToCode( const char* pszMnemonic )
     518                 : {
     519               6 :     if ( EQUAL(pszMnemonic, "UTM") )
     520               1 :         return 1L;
     521               5 :     else if ( EQUAL(pszMnemonic, "LCC") )
     522               1 :         return 4L;
     523               4 :     else if ( EQUAL(pszMnemonic, "PS") )
     524               0 :         return 6L;
     525               4 :     else if ( EQUAL(pszMnemonic, "PC") )
     526               0 :         return 7L;
     527               4 :     else if ( EQUAL(pszMnemonic, "TM") )
     528               3 :         return 9L;
     529               1 :     else if ( EQUAL(pszMnemonic, "OM") )
     530               0 :         return 20L;
     531               1 :     else if ( EQUAL(pszMnemonic, "SOM") )
     532               1 :         return 22L;
     533                 :     else
     534               0 :         return 1L;  // UTM by default
     535                 : }
     536                 : 
     537                 : /************************************************************************/
     538                 : /*                        USGSEllipsoidToCode()                         */
     539                 : /************************************************************************/
     540                 : 
     541               7 : static long USGSEllipsoidToCode( const char* pszMnemonic )
     542                 : {
     543               7 :     if ( EQUAL(pszMnemonic, "CLARKE_1866") )
     544               0 :         return 0L;
     545               7 :     else if ( EQUAL(pszMnemonic, "CLARKE_1880") )
     546               0 :         return 1L;
     547               7 :     else if ( EQUAL(pszMnemonic, "BESSEL") )
     548               0 :         return 2L;
     549               7 :     else if ( EQUAL(pszMnemonic, "INTERNATL_1967") )
     550               0 :         return 3L;
     551               7 :     else if ( EQUAL(pszMnemonic, "INTERNATL_1909") )
     552               2 :         return 4L;
     553               5 :     else if ( EQUAL(pszMnemonic, "WGS72") || EQUAL(pszMnemonic, "WGS_72") )
     554               0 :         return 5L;
     555               5 :     else if ( EQUAL(pszMnemonic, "EVEREST") )
     556               0 :         return 6L;
     557               5 :     else if ( EQUAL(pszMnemonic, "WGS66") || EQUAL(pszMnemonic, "WGS_66") )
     558               0 :         return 7L;
     559               5 :     else if ( EQUAL(pszMnemonic, "GRS_80") )
     560               0 :         return 8L;
     561               5 :     else if ( EQUAL(pszMnemonic, "AIRY") )
     562               0 :         return 9L;
     563               5 :     else if ( EQUAL(pszMnemonic, "MODIFIED_EVEREST") )
     564               0 :         return 10L;
     565               5 :     else if ( EQUAL(pszMnemonic, "MODIFIED_AIRY") )
     566               0 :         return 11L;
     567               5 :     else if ( EQUAL(pszMnemonic, "WGS84") || EQUAL(pszMnemonic, "WGS_84") )
     568               4 :         return 12L;
     569               1 :     else if ( EQUAL(pszMnemonic, "SOUTHEAST_ASIA") )
     570               0 :         return 13L;
     571               1 :     else if ( EQUAL(pszMnemonic, "AUSTRALIAN_NATL") )
     572               0 :         return 14L;
     573               1 :     else if ( EQUAL(pszMnemonic, "KRASSOVSKY") )
     574               0 :         return 15L;
     575               1 :     else if ( EQUAL(pszMnemonic, "HOUGH") )
     576               0 :         return 16L;
     577               1 :     else if ( EQUAL(pszMnemonic, "MERCURY_1960") )
     578               0 :         return 17L;
     579               1 :     else if ( EQUAL(pszMnemonic, "MOD_MERC_1968") )
     580               0 :         return 18L;
     581               1 :     else if ( EQUAL(pszMnemonic, "6370997_M_SPHERE") )
     582               0 :         return 19L;
     583                 :     else
     584               1 :         return 0L;
     585                 : }
     586                 : 
     587                 : /************************************************************************/
     588                 : /*                                Open()                                */
     589                 : /************************************************************************/
     590                 : 
     591           12040 : GDALDataset *FASTDataset::Open( GDALOpenInfo * poOpenInfo )
     592                 : 
     593                 : {
     594                 :     int   i;
     595                 : 
     596           12040 :     if( poOpenInfo->nHeaderBytes < 1024)
     597           11498 :         return NULL;
     598                 : 
     599             542 :     if( !EQUALN((const char *) poOpenInfo->pabyHeader + 52,
     600                 :     "ACQUISITION DATE =", 18)
     601                 :         && !EQUALN((const char *) poOpenInfo->pabyHeader + 36,
     602                 :     "ACQUISITION DATE =", 18) )
     603             535 :         return NULL;
     604                 :     
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*  Create a corresponding GDALDataset.                                 */
     607                 : /* -------------------------------------------------------------------- */
     608                 :     FASTDataset *poDS;
     609                 : 
     610               7 :     poDS = new FASTDataset();
     611                 : 
     612               7 :     poDS->fpHeader = VSIFOpenL(poOpenInfo->pszFilename, "rb");
     613               7 :     if (poDS->fpHeader == NULL)
     614                 :     {
     615               0 :         delete poDS;
     616               0 :         return NULL;
     617                 :     }
     618                 : 
     619               7 :     poDS->pszFilename = poOpenInfo->pszFilename;
     620               7 :     poDS->pszDirname = CPLStrdup( CPLGetDirname( poOpenInfo->pszFilename ) );
     621                 :     
     622                 : /* -------------------------------------------------------------------- */
     623                 : /*  Read the administrative record.                                     */
     624                 : /* -------------------------------------------------------------------- */
     625                 :     char  *pszTemp;
     626               7 :     char  *pszHeader = (char *) CPLMalloc( ADM_HEADER_SIZE + 1 );
     627                 :     size_t      nBytesRead;
     628                 :  
     629               7 :     VSIFSeekL( poDS->fpHeader, 0, SEEK_SET );
     630               7 :     nBytesRead = VSIFReadL( pszHeader, 1, ADM_HEADER_SIZE, poDS->fpHeader );
     631               7 :     if ( nBytesRead < ADM_MIN_HEADER_SIZE )
     632                 :     {
     633               0 :   CPLDebug( "FAST", "Header file too short. Reading failed" );
     634               0 :         CPLFree(pszHeader);
     635               0 :   delete poDS;
     636               0 :   return NULL;
     637                 :     }
     638               7 :     pszHeader[nBytesRead] = '\0';
     639                 : 
     640                 :     // Read acquisition date
     641                 :     pszTemp = GetValue( pszHeader, ACQUISITION_DATE,
     642               7 :                         ACQUISITION_DATE_SIZE, TRUE );
     643               7 :     if (pszTemp == NULL)
     644                 :     {
     645               0 :         CPLDebug( "FAST", "Cannot get ACQUISITION_DATE, using empty value." );
     646               0 :         pszTemp = CPLStrdup("");
     647                 :     }
     648               7 :     poDS->SetMetadataItem( "ACQUISITION_DATE", pszTemp );
     649               7 :     CPLFree( pszTemp );
     650                 : 
     651                 :     // Read satellite name (will read the first one only)
     652               7 :     pszTemp = GetValue( pszHeader, SATELLITE_NAME, SATELLITE_NAME_SIZE, TRUE );
     653               7 :     if (pszTemp == NULL)
     654                 :     {
     655               0 :         CPLDebug( "FAST", "Cannot get SATELLITE_NAME, using empty value." );
     656               0 :         pszTemp = CPLStrdup( "" );
     657                 :     }
     658               7 :     poDS->SetMetadataItem( "SATELLITE", pszTemp );
     659               7 :     if ( EQUALN(pszTemp, "LANDSAT", 7) )
     660               3 :   poDS->iSatellite = LANDSAT;
     661               4 :     else if ( EQUALN(pszTemp, "IRS", 3) )
     662               3 :   poDS->iSatellite = IRS;
     663                 :     else
     664               1 :   poDS->iSatellite = IRS;
     665               7 :     CPLFree( pszTemp );
     666                 : 
     667                 :     // Read sensor name (will read the first one only)
     668               7 :     pszTemp = GetValue( pszHeader, SENSOR_NAME, SENSOR_NAME_SIZE, TRUE );
     669               7 :     if (pszTemp == NULL)
     670                 :     {
     671               1 :         CPLDebug( "FAST", "Cannot get SENSOR_NAME, using empty value." );
     672               1 :         pszTemp = CPLStrdup("");
     673                 :     }
     674               7 :     poDS->SetMetadataItem( "SENSOR", pszTemp );
     675               7 :     CPLFree( pszTemp );
     676                 : 
     677                 :     // Read filenames
     678               7 :     poDS->nBands = 0;
     679                 :     
     680               7 :     if (strstr( pszHeader, FILENAME ) == NULL)
     681                 :     {
     682               4 :         if (strstr(pszHeader, "GENERATING AGENCY =EUROMAP"))
     683                 :         {
     684                 :             /* If we don't find the FILENAME field, let's try with the Euromap */
     685                 :             /* PAN / LISS3 / WIFS IRS filename convention */
     686              11 :             if ((EQUAL(poDS->GetMetadataItem("SATELLITE"), "IRS 1C") ||
     687               2 :                  EQUAL(poDS->GetMetadataItem("SATELLITE"), "IRS 1D")) &&
     688               3 :                 (EQUAL(poDS->GetMetadataItem("SENSOR"), "PAN") ||
     689               2 :                  EQUAL(poDS->GetMetadataItem("SENSOR"), "LISS3") ||
     690               1 :                  EQUAL(poDS->GetMetadataItem("SENSOR"), "WIFS")))
     691                 :             {
     692               3 :                 poDS->TryEuromap_IRS_1C_1D_ChannelNameConvention();
     693                 :             }
     694               0 :             else if (EQUAL(poDS->GetMetadataItem("SATELLITE"), "CARTOSAT-1") &&
     695               0 :                      (EQUAL(poDS->GetMetadataItem("SENSOR"), "FORE") ||
     696               0 :                       EQUAL(poDS->GetMetadataItem("SENSOR"), "AFT")))
     697                 :             {
     698                 :                 /* See http://www.euromap.de/download/p5fast_20050301.pdf, appendix F */
     699               0 :                 CPLString     osSuffix = CPLGetExtension( poDS->pszFilename );
     700               0 :                 const char    *papszBasenames[] = { "BANDF", "bandf", "BANDA", "banda" };
     701               0 :                 for ( i=0;i<4;i++)
     702                 :                 {
     703               0 :                     CPLString osChannelFilename = CPLFormFilename( poDS->pszDirname, papszBasenames[i], osSuffix );
     704               0 :                     if (poDS->OpenChannel( osChannelFilename, 0 ))
     705                 :                     {
     706               0 :                         poDS->nBands = 1;
     707                 :                         break;
     708                 :                     }
     709               0 :                 }
     710                 :             }
     711               0 :             else if (EQUAL(poDS->GetMetadataItem("SATELLITE"), "IRS P6"))
     712                 :             {
     713                 :                 /* If BANDS_PRESENT="2345", the file bands are "BAND2.DAT", "BAND3.DAT", etc. */
     714               0 :                 pszTemp = GetValue( pszHeader, BANDS_PRESENT, BANDS_PRESENT_SIZE, TRUE );
     715               0 :                 if (pszTemp)
     716                 :                 {
     717               0 :                     for( i=0; pszTemp[i] != '\0'; i++)
     718                 :                     {
     719               0 :                         if (pszTemp[i] >= '2' && pszTemp[i] <= '5')
     720                 :                         {
     721               0 :                             if (poDS->FOpenChannel(poDS->pszFilename, poDS->nBands, pszTemp[i] - '0'))
     722               0 :                                 poDS->nBands++;
     723                 :                         }
     724                 :                     }
     725               0 :                     CPLFree( pszTemp );
     726                 :                 }
     727                 :             }
     728                 :         }
     729                 :     }
     730                 :     
     731                 :     /* If the previous lookup for band files didn't success, fallback to the */
     732                 :     /* standard way of finding them, either by the FILENAME field, either with */
     733                 :     /* the usual patterns like bandX.dat, etc... */
     734               7 :     if ( !poDS->nBands )
     735                 :     {
     736               4 :         pszTemp = pszHeader;
     737              32 :         for ( i = 0; i < 7; i++ )
     738                 :         {
     739              28 :             char *pszFilename = NULL ;
     740              28 :             if ( pszTemp )
     741              22 :                 pszTemp = strstr( pszTemp, FILENAME );
     742              28 :             if ( pszTemp )
     743                 :             {
     744                 :                 // Skip the parameter name
     745              18 :                 pszTemp += strlen(FILENAME);
     746                 :                 // Skip whitespaces and equal signs
     747              54 :                 while ( *pszTemp == ' ' )
     748              18 :                     pszTemp++;
     749              54 :                 while ( *pszTemp == '=' )
     750              18 :                     pszTemp++;
     751              18 :                 pszFilename = CPLScanString( pszTemp, FILENAME_SIZE, TRUE, FALSE );
     752                 :             }
     753                 :             else
     754              10 :                 pszTemp = NULL;
     755              28 :             if ( poDS->FOpenChannel( pszFilename, poDS->nBands, poDS->nBands + 1 ) )
     756              11 :                 poDS->nBands++;
     757              28 :             if ( pszFilename )
     758              18 :                 CPLFree( pszFilename );
     759                 :         }
     760                 :     }
     761                 : 
     762               7 :     if ( !poDS->nBands )
     763                 :     {
     764                 :   CPLError( CE_Failure, CPLE_NotSupported,
     765               0 :                   "Failed to find and open band data files." );
     766               0 :         CPLFree(pszHeader);
     767               0 :   delete poDS;
     768               0 :   return NULL;
     769                 :     }
     770                 : 
     771                 :     // Read number of pixels/lines and bit depth
     772               7 :     pszTemp = GetValue( pszHeader, PIXELS, PIXELS_SIZE, FALSE );
     773               7 :     if ( pszTemp )
     774                 :     {
     775               7 :         poDS->nRasterXSize = atoi( pszTemp );
     776               7 :         CPLFree( pszTemp );
     777                 :     }
     778                 :     else
     779                 :     {
     780               0 :         CPLDebug( "FAST", "Failed to find number of pixels in line." );
     781               0 :         CPLFree(pszHeader);
     782               0 :         delete poDS;
     783               0 :   return NULL;
     784                 :     }
     785                 : 
     786               7 :     pszTemp = GetValue( pszHeader, LINES1, LINES_SIZE, FALSE );
     787               7 :     if ( !pszTemp )
     788               1 :         pszTemp = GetValue( pszHeader, LINES2, LINES_SIZE, FALSE );
     789               7 :     if ( pszTemp )
     790                 :     {
     791               7 :         poDS->nRasterYSize = atoi( pszTemp );
     792               7 :         CPLFree( pszTemp );
     793                 :     }
     794                 :     else
     795                 :     {
     796               0 :         CPLDebug( "FAST", "Failed to find number of lines in raster." );
     797               0 :         CPLFree(pszHeader);
     798               0 :         delete poDS;
     799               0 :   return NULL;
     800                 :     }
     801                 : 
     802                 : 
     803                 :     
     804               7 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     805                 :     {
     806               0 :         CPLFree(pszHeader);
     807               0 :         delete poDS;
     808               0 :         return NULL;
     809                 :     }
     810                 : 
     811               7 :     pszTemp = GetValue( pszHeader, BITS_PER_PIXEL, BITS_PER_PIXEL_SIZE, FALSE );
     812               7 :     if ( pszTemp )
     813                 :     {
     814               6 :         switch( atoi(pszTemp) )
     815                 :         {
     816                 :             case 8:
     817                 :             default:
     818               6 :                 poDS->eDataType = GDT_Byte;
     819               6 :                 break;
     820                 :             case 10: /* For a strange reason, some Euromap products declare 10 bits output, but are 16 bits */
     821                 :             case 16:
     822               0 :                 poDS->eDataType = GDT_UInt16;
     823                 :                 break;
     824                 :         }
     825               6 :         CPLFree( pszTemp );
     826                 :     }
     827                 :     else
     828               1 :         poDS->eDataType = GDT_Byte;
     829                 : 
     830                 : /* -------------------------------------------------------------------- */
     831                 : /*  Read radiometric record.              */
     832                 : /* -------------------------------------------------------------------- */
     833                 :     const char  *pszFirst, *pszSecond;
     834                 : 
     835                 :     // Read gains and biases. This is a trick!
     836               7 :     pszTemp = strstr( pszHeader, "BIASES" );// It may be "BIASES AND GAINS"
     837                 :                                             // or "GAINS AND BIASES"
     838               7 :     if ( pszTemp > strstr( pszHeader, "GAINS" ) )
     839                 :     {
     840               3 :         pszFirst = "GAIN%d";
     841               3 :         pszSecond = "BIAS%d";
     842                 :     }
     843                 :     else
     844                 :     {
     845               4 :         pszFirst = "BIAS%d";
     846               4 :         pszSecond = "GAIN%d";
     847                 :     }
     848                 : 
     849                 :     // Now search for the first number occurance after that string
     850              25 :     for ( i = 1; i <= poDS->nBands; i++ )
     851                 :     {
     852              18 :         char    *pszValue = NULL;
     853              18 :         size_t  nValueLen = VALUE_SIZE;
     854                 : 
     855              18 :         pszTemp = strpbrk( pszTemp, "-.0123456789" );
     856              18 :         if ( pszTemp )
     857                 :         {
     858              18 :             nValueLen = strspn( pszTemp, "+-.0123456789" );
     859              18 :             pszValue = CPLScanString( pszTemp, nValueLen, TRUE, TRUE );
     860              18 :             poDS->SetMetadataItem( CPLSPrintf(pszFirst, i ), pszValue );
     861              18 :             CPLFree( pszValue );
     862                 :         }
     863              18 :         pszTemp += nValueLen;
     864              18 :         pszTemp = strpbrk( pszTemp, "-.0123456789" );
     865              18 :         if ( pszTemp )
     866                 :         {
     867              18 :             nValueLen = strspn( pszTemp, "+-.0123456789" );
     868              18 :             pszValue = CPLScanString( pszTemp, nValueLen, TRUE, TRUE );
     869              18 :             poDS->SetMetadataItem( CPLSPrintf(pszSecond, i ), pszValue );
     870              18 :             CPLFree( pszValue );
     871                 :         }
     872              18 :         pszTemp += nValueLen;
     873                 :     }
     874                 : 
     875                 : /* -------------------------------------------------------------------- */
     876                 : /*  Read geometric record.                  */
     877                 : /* -------------------------------------------------------------------- */
     878               7 :     OGRSpatialReference oSRS;
     879                 :     long        iProjSys, iZone, iDatum;
     880                 :     // Coordinates of pixel's centers
     881               7 :     double  dfULX = 0.0, dfULY = 0.0;
     882               7 :     double  dfURX = 0.0, dfURY = 0.0;
     883               7 :     double  dfLLX = 0.0, dfLLY = 0.0;
     884               7 :     double  dfLRX = 0.0, dfLRY = 0.0;
     885                 :     double      adfProjParms[15];
     886                 : 
     887                 :     // Read projection name
     888                 :     pszTemp = GetValue( pszHeader, PROJECTION_NAME,
     889               7 :                         PROJECTION_NAME_SIZE, FALSE );
     890              13 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     891               6 :         iProjSys = USGSMnemonicToCode( pszTemp );
     892                 :     else
     893               1 :         iProjSys = 1L;  // UTM by default
     894               7 :     CPLFree( pszTemp );
     895                 : 
     896                 :     // Read ellipsoid name
     897               7 :     pszTemp = GetValue( pszHeader, ELLIPSOID_NAME, ELLIPSOID_NAME_SIZE, FALSE );
     898              14 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     899               7 :         iDatum = USGSEllipsoidToCode( pszTemp );
     900                 :     else
     901               0 :         iDatum = 0L;   // Clarke, 1866 (NAD1927) by default
     902               7 :     CPLFree( pszTemp );
     903                 : 
     904                 :     // Read zone number
     905               7 :     pszTemp = GetValue( pszHeader, ZONE_NUMBER, ZONE_NUMBER_SIZE, FALSE );
     906              11 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     907               4 :         iZone = atoi( pszTemp );
     908                 :     else
     909               3 :         iZone = 0L;
     910               7 :     CPLFree( pszTemp );
     911                 : 
     912                 :     // Read 15 USGS projection parameters
     913             112 :     for ( i = 0; i < 15; i++ )
     914             105 :         adfProjParms[i] = 0.0;
     915               7 :     pszTemp = strstr( pszHeader, USGS_PARAMETERS );
     916               7 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     917                 :     {
     918               7 :         pszTemp += strlen( USGS_PARAMETERS );
     919             112 :         for ( i = 0; i < 15; i++ )
     920                 :         {
     921             105 :             pszTemp = strpbrk( pszTemp, "-.0123456789" );
     922             105 :             if ( pszTemp )
     923             105 :                 adfProjParms[i] = CPLScanDouble( pszTemp, VALUE_SIZE );
     924             105 :             pszTemp = strpbrk( pszTemp, " \t" );
     925                 :         }
     926                 :     }
     927                 : 
     928                 :     // Coordinates should follow the word "PROJECTION", otherwise we can
     929                 :     // be confused by other occurences of the corner keywords.
     930               7 :     char        *pszGeomRecord = strstr( pszHeader, "PROJECTION" );
     931                 :     // Read corner coordinates
     932               7 :     pszTemp = strstr( pszGeomRecord, CORNER_UPPER_LEFT );
     933               7 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     934                 :     {
     935               7 :         pszTemp += strlen( CORNER_UPPER_LEFT ) + 28;
     936               7 :         dfULX = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     937               7 :         pszTemp += CORNER_VALUE_SIZE + 1;
     938               7 :         dfULY = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     939                 :     }
     940                 : 
     941               7 :     pszTemp = strstr( pszGeomRecord, CORNER_UPPER_RIGHT );
     942               7 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     943                 :     {
     944               7 :         pszTemp += strlen( CORNER_UPPER_RIGHT ) + 28;
     945               7 :         dfURX = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     946               7 :         pszTemp += CORNER_VALUE_SIZE + 1;
     947               7 :         dfURY = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     948                 :     }
     949                 : 
     950               7 :     pszTemp = strstr( pszGeomRecord, CORNER_LOWER_LEFT );
     951               7 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     952                 :     {
     953               7 :         pszTemp += strlen( CORNER_LOWER_LEFT ) + 28;
     954               7 :         dfLLX = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     955               7 :         pszTemp += CORNER_VALUE_SIZE + 1;
     956               7 :         dfLLY = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     957                 :     }
     958                 : 
     959               7 :     pszTemp = strstr( pszGeomRecord, CORNER_LOWER_RIGHT );
     960               7 :     if ( pszTemp && !EQUAL( pszTemp, "" ) )
     961                 :     {
     962               7 :         pszTemp += strlen( CORNER_LOWER_RIGHT ) + 28;
     963               7 :         dfLRX = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     964               7 :         pszTemp += CORNER_VALUE_SIZE + 1;
     965               7 :         dfLRY = CPLScanDouble( pszTemp, CORNER_VALUE_SIZE );
     966                 :     }
     967                 : 
     968               7 :     if ( dfULX != 0.0 && dfULY != 0.0
     969                 :          && dfURX != 0.0 && dfURY != 0.0
     970                 :          && dfLLX != 0.0 && dfLLY != 0.0
     971                 :          && dfLRX != 0.0 && dfLRY != 0.0 )
     972                 :     {
     973               7 :         int transform_ok=FALSE;
     974                 :         GDAL_GCP *pasGCPList;
     975                 :         int bAnglesInPackedDMSFormat;
     976                 : 
     977                 :         // Strip out zone number from the easting values, if either
     978               7 :         if ( dfULX >= 1000000.0 )
     979               2 :             dfULX -= (double)iZone * 1000000.0;
     980               7 :         if ( dfURX >= 1000000.0 )
     981               2 :             dfURX -= (double)iZone * 1000000.0;
     982               7 :         if ( dfLLX >= 1000000.0 )
     983               2 :             dfLLX -= (double)iZone * 1000000.0;
     984               7 :         if ( dfLRX >= 1000000.0 )
     985               2 :             dfLRX -= (double)iZone * 1000000.0;
     986                 : 
     987                 :         // In EOSAT FAST Rev C, the angles are in decimal degrees
     988                 :         // otherwise they are in packed DMS format.
     989               7 :         if (strstr(pszHeader, "REV            C") != NULL)
     990               3 :             bAnglesInPackedDMSFormat = FALSE;
     991                 :         else
     992               4 :             bAnglesInPackedDMSFormat = TRUE;
     993                 : 
     994                 :         // Create projection definition
     995                 :         OGRErr eErr =
     996               7 :             oSRS.importFromUSGS( iProjSys, iZone, adfProjParms, iDatum, bAnglesInPackedDMSFormat );
     997               7 :         if ( eErr != OGRERR_NONE )
     998               0 :             CPLDebug("FAST", "Import projection from USGS failed: %d", eErr);
     999               7 :         oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
    1000                 :         
    1001                 :         // Read datum name
    1002               7 :         pszTemp = GetValue( pszHeader, DATUM_NAME, DATUM_NAME_SIZE, FALSE );
    1003               7 :         if ( pszTemp )
    1004                 :         {
    1005               6 :             if ( EQUAL( pszTemp, "WGS84" ) )
    1006               3 :                 oSRS.SetWellKnownGeogCS( "WGS84" );
    1007               3 :             else if ( EQUAL( pszTemp, "NAD27" ) )
    1008               0 :                 oSRS.SetWellKnownGeogCS( "NAD27" );
    1009               3 :             else if ( EQUAL( pszTemp, "NAD83" ) )
    1010               0 :                 oSRS.SetWellKnownGeogCS( "NAD83" );
    1011               6 :             CPLFree( pszTemp );
    1012                 :         }
    1013                 :         else
    1014                 :         {
    1015                 :             // Reasonable fallback
    1016               1 :             oSRS.SetWellKnownGeogCS( "WGS84" );
    1017                 :         }
    1018                 : 
    1019               7 :         if ( poDS->pszProjection )
    1020               7 :             CPLFree( poDS->pszProjection );
    1021               7 :         eErr = oSRS.exportToWkt( &poDS->pszProjection );
    1022               7 :         if ( eErr != OGRERR_NONE )
    1023               0 :             CPLDebug("FAST", "Export projection to WKT USGS failed: %d", eErr);
    1024                 : 
    1025                 :         // Generate GCPs
    1026               7 :         pasGCPList = (GDAL_GCP *) CPLCalloc( sizeof( GDAL_GCP ), 4 );
    1027               7 :         GDALInitGCPs( 4, pasGCPList );
    1028               7 :         CPLFree(pasGCPList[0].pszId);
    1029               7 :         CPLFree(pasGCPList[1].pszId);
    1030               7 :         CPLFree(pasGCPList[2].pszId);
    1031               7 :         CPLFree(pasGCPList[3].pszId);
    1032                 : 
    1033                 :         /* Let's order the GCP in TL, TR, BR, BL order to benefit from the */
    1034                 :         /* GDALGCPsToGeoTransform optimization */ 
    1035               7 :         pasGCPList[0].pszId = CPLStrdup("UPPER_LEFT");
    1036               7 :         pasGCPList[0].dfGCPX = dfULX;
    1037               7 :         pasGCPList[0].dfGCPY = dfULY;
    1038               7 :         pasGCPList[0].dfGCPZ = 0.0;
    1039               7 :         pasGCPList[0].dfGCPPixel = 0.5;
    1040               7 :         pasGCPList[0].dfGCPLine = 0.5;
    1041               7 :         pasGCPList[1].pszId = CPLStrdup("UPPER_RIGHT");
    1042               7 :         pasGCPList[1].dfGCPX = dfURX;
    1043               7 :         pasGCPList[1].dfGCPY = dfURY;
    1044               7 :         pasGCPList[1].dfGCPZ = 0.0;
    1045               7 :         pasGCPList[1].dfGCPPixel = poDS->nRasterXSize-0.5;
    1046               7 :         pasGCPList[1].dfGCPLine = 0.5;
    1047               7 :         pasGCPList[2].pszId = CPLStrdup("LOWER_RIGHT");
    1048               7 :         pasGCPList[2].dfGCPX = dfLRX;
    1049               7 :         pasGCPList[2].dfGCPY = dfLRY;
    1050               7 :         pasGCPList[2].dfGCPZ = 0.0;
    1051               7 :         pasGCPList[2].dfGCPPixel = poDS->nRasterXSize-0.5;
    1052               7 :         pasGCPList[2].dfGCPLine = poDS->nRasterYSize-0.5;
    1053               7 :         pasGCPList[3].pszId = CPLStrdup("LOWER_LEFT");
    1054               7 :         pasGCPList[3].dfGCPX = dfLLX;
    1055               7 :         pasGCPList[3].dfGCPY = dfLLY;
    1056               7 :         pasGCPList[3].dfGCPZ = 0.0;
    1057               7 :         pasGCPList[3].dfGCPPixel = 0.5;
    1058               7 :         pasGCPList[3].dfGCPLine = poDS->nRasterYSize-0.5;
    1059                 : 
    1060                 :         // Calculate transformation matrix, if accurate
    1061                 :         transform_ok =
    1062               7 :             GDALGCPsToGeoTransform(4,pasGCPList,poDS->adfGeoTransform,0);
    1063               7 :         if (transform_ok == FALSE)
    1064                 :         {
    1065                 :             
    1066               0 :             poDS->adfGeoTransform[0] = 0.0;
    1067               0 :             poDS->adfGeoTransform[1] = 1.0;
    1068               0 :             poDS->adfGeoTransform[2] = 0.0;
    1069               0 :             poDS->adfGeoTransform[3] = 0.0;
    1070               0 :             poDS->adfGeoTransform[4] = 0.0;
    1071               0 :             poDS->adfGeoTransform[5] = 1.0;
    1072               0 :             if ( poDS->pszProjection )
    1073               0 :                 CPLFree( poDS->pszProjection );
    1074               0 :             poDS->pszProjection = CPLStrdup("");
    1075                 :         }
    1076                 : 
    1077               7 :         GDALDeinitGCPs(4, pasGCPList);
    1078               7 :         CPLFree(pasGCPList);
    1079                 :     }
    1080                 : 
    1081                 : /* -------------------------------------------------------------------- */
    1082                 : /*      Create band information objects.                                */
    1083                 : /* -------------------------------------------------------------------- */
    1084               7 :     int nPixelOffset = GDALGetDataTypeSize(poDS->eDataType) / 8;
    1085               7 :     int nLineOffset = poDS->nRasterXSize * nPixelOffset;
    1086                 : 
    1087              25 :     for( i = 1; i <= poDS->nBands; i++ )
    1088                 :     {
    1089                 :         poDS->SetBand( i, new FASTRasterBand( poDS, i, poDS->fpChannels[i - 1],
    1090              18 :       0, nPixelOffset, nLineOffset, poDS->eDataType, TRUE));
    1091                 :     }
    1092                 : 
    1093               7 :     CPLFree( pszHeader );
    1094                 : 
    1095                 : /* -------------------------------------------------------------------- */
    1096                 : /*      Initialize any PAM information.                                 */
    1097                 : /* -------------------------------------------------------------------- */
    1098               7 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1099               7 :     poDS->TryLoadXML();
    1100                 :     
    1101                 :     // opens overviews.
    1102               7 :     poDS->oOvManager.Initialize(poDS, poDS->pszFilename);
    1103                 :     
    1104                 : /* -------------------------------------------------------------------- */
    1105                 : /*      Confirm the requested access is supported.                      */
    1106                 : /* -------------------------------------------------------------------- */
    1107               7 :     if( poOpenInfo->eAccess == GA_Update )
    1108                 :     {
    1109               0 :         delete poDS;
    1110                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1111                 :                   "The FAST driver does not support update access to existing"
    1112               0 :                   " datasets.\n" );
    1113               0 :         return NULL;
    1114                 :     }
    1115                 :     
    1116               7 :     return( poDS );
    1117                 : }
    1118                 : 
    1119                 : /************************************************************************/
    1120                 : /*                        GDALRegister_FAST()       */
    1121                 : /************************************************************************/
    1122                 : 
    1123             582 : void GDALRegister_FAST()
    1124                 : 
    1125                 : {
    1126                 :     GDALDriver  *poDriver;
    1127                 : 
    1128             582 :     if( GDALGetDriverByName( "FAST" ) == NULL )
    1129                 :     {
    1130             561 :         poDriver = new GDALDriver();
    1131                 :         
    1132             561 :         poDriver->SetDescription( "FAST" );
    1133                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1134             561 :                                    "EOSAT FAST Format" );
    1135                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1136             561 :                                    "frmt_fast.html" );
    1137             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1138                 : 
    1139             561 :         poDriver->pfnOpen = FASTDataset::Open;
    1140                 : 
    1141             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1142                 :     }
    1143             582 : }
    1144                 : 

Generated by: LCOV version 1.7