LCOV - code coverage report
Current view: directory - frmts/raw - envidataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1018 739 72.6 %
Date: 2013-03-30 Functions: 41 32 78.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: envidataset.cpp 25660 2013-02-21 20:56:07Z rouault $
       3                 :  *
       4                 :  * Project:  ENVI .hdr Driver
       5                 :  * Purpose:  Implementation of ENVI .hdr labelled raw raster support.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  * Maintainer: Chris Padwick (cpadwick at ittvis.com)
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2002, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "rawdataset.h"
      32                 : #include "ogr_spatialref.h"
      33                 : #include "cpl_string.h"
      34                 : #include <algorithm>
      35                 : 
      36                 : CPL_CVSID("$Id: envidataset.cpp 25660 2013-02-21 20:56:07Z rouault $");
      37                 : 
      38                 : CPL_C_START
      39                 : void GDALRegister_ENVI(void);
      40                 : CPL_C_END
      41                 : 
      42                 : static const int anUsgsEsriZones[] =
      43                 : {
      44                 :   101, 3101,
      45                 :   102, 3126,
      46                 :   201, 3151,
      47                 :   202, 3176,
      48                 :   203, 3201,
      49                 :   301, 3226,
      50                 :   302, 3251,
      51                 :   401, 3276,
      52                 :   402, 3301,
      53                 :   403, 3326,
      54                 :   404, 3351,
      55                 :   405, 3376,
      56                 :   406, 3401,
      57                 :   407, 3426,
      58                 :   501, 3451,
      59                 :   502, 3476,
      60                 :   503, 3501,
      61                 :   600, 3526,
      62                 :   700, 3551,
      63                 :   901, 3601,
      64                 :   902, 3626,
      65                 :   903, 3576,
      66                 :  1001, 3651,
      67                 :  1002, 3676,
      68                 :  1101, 3701,
      69                 :  1102, 3726,
      70                 :  1103, 3751,
      71                 :  1201, 3776,
      72                 :  1202, 3801,
      73                 :  1301, 3826,
      74                 :  1302, 3851,
      75                 :  1401, 3876,
      76                 :  1402, 3901,
      77                 :  1501, 3926,
      78                 :  1502, 3951,
      79                 :  1601, 3976,
      80                 :  1602, 4001,
      81                 :  1701, 4026,
      82                 :  1702, 4051,
      83                 :  1703, 6426,
      84                 :  1801, 4076,
      85                 :  1802, 4101,
      86                 :  1900, 4126,
      87                 :  2001, 4151,
      88                 :  2002, 4176,
      89                 :  2101, 4201,
      90                 :  2102, 4226,
      91                 :  2103, 4251,
      92                 :  2111, 6351,
      93                 :  2112, 6376,
      94                 :  2113, 6401,
      95                 :  2201, 4276,
      96                 :  2202, 4301,
      97                 :  2203, 4326,
      98                 :  2301, 4351,
      99                 :  2302, 4376,
     100                 :  2401, 4401,
     101                 :  2402, 4426,
     102                 :  2403, 4451,
     103                 :  2500,    0,
     104                 :  2501, 4476,
     105                 :  2502, 4501,
     106                 :  2503, 4526,
     107                 :  2600,    0,
     108                 :  2601, 4551,
     109                 :  2602, 4576,
     110                 :  2701, 4601,
     111                 :  2702, 4626,
     112                 :  2703, 4651,
     113                 :  2800, 4676,
     114                 :  2900, 4701,
     115                 :  3001, 4726,
     116                 :  3002, 4751,
     117                 :  3003, 4776,
     118                 :  3101, 4801,
     119                 :  3102, 4826,
     120                 :  3103, 4851,
     121                 :  3104, 4876,
     122                 :  3200, 4901,
     123                 :  3301, 4926,
     124                 :  3302, 4951,
     125                 :  3401, 4976,
     126                 :  3402, 5001,
     127                 :  3501, 5026,
     128                 :  3502, 5051,
     129                 :  3601, 5076,
     130                 :  3602, 5101,
     131                 :  3701, 5126,
     132                 :  3702, 5151,
     133                 :  3800, 5176,
     134                 :  3900,    0,
     135                 :  3901, 5201,
     136                 :  3902, 5226,
     137                 :  4001, 5251,
     138                 :  4002, 5276,
     139                 :  4100, 5301,
     140                 :  4201, 5326,
     141                 :  4202, 5351,
     142                 :  4203, 5376,
     143                 :  4204, 5401,
     144                 :  4205, 5426,
     145                 :  4301, 5451,
     146                 :  4302, 5476,
     147                 :  4303, 5501,
     148                 :  4400, 5526,
     149                 :  4501, 5551,
     150                 :  4502, 5576,
     151                 :  4601, 5601,
     152                 :  4602, 5626,
     153                 :  4701, 5651,
     154                 :  4702, 5676,
     155                 :  4801, 5701,
     156                 :  4802, 5726,
     157                 :  4803, 5751,
     158                 :  4901, 5776,
     159                 :  4902, 5801,
     160                 :  4903, 5826,
     161                 :  4904, 5851,
     162                 :  5001, 6101,
     163                 :  5002, 6126,
     164                 :  5003, 6151,
     165                 :  5004, 6176,
     166                 :  5005, 6201,
     167                 :  5006, 6226,
     168                 :  5007, 6251,
     169                 :  5008, 6276,
     170                 :  5009, 6301,
     171                 :  5010, 6326,
     172                 :  5101, 5876,
     173                 :  5102, 5901,
     174                 :  5103, 5926,
     175                 :  5104, 5951,
     176                 :  5105, 5976,
     177                 :  5201, 6001,
     178                 :  5200, 6026,
     179                 :  5200, 6076,
     180                 :  5201, 6051,
     181                 :  5202, 6051,
     182                 :  5300,    0, 
     183                 :  5400,    0
     184                 : };
     185                 : 
     186                 : /************************************************************************/
     187                 : /*                           ITTVISToUSGSZone()                         */
     188                 : /*                                                                      */
     189                 : /*      Convert ITTVIS style state plane zones to NOS style state       */
     190                 : /*      plane zones.  The ENVI default is to use the new NOS zones,     */
     191                 : /*      but the old state plane zones can be used.  Handle this.        */ 
     192                 : /************************************************************************/
     193                 : 
     194               0 : static int ITTVISToUSGSZone( int nITTVISZone )
     195                 : 
     196                 : {
     197               0 :     int   nPairs = sizeof(anUsgsEsriZones) / (2*sizeof(int));
     198                 :     int   i;
     199                 :     
     200                 :   // Default is to use the zone as-is, as long as it is in the 
     201                 :   // available list
     202               0 :     for( i = 0; i < nPairs; i++ )
     203                 :     {
     204               0 :         if( anUsgsEsriZones[i*2] == nITTVISZone )
     205               0 :             return anUsgsEsriZones[i*2];
     206                 :     }
     207                 : 
     208                 :   // If not found in the new style, see if it is present in the
     209                 :   // old style list and convert it.  We don't expect to see this
     210                 :   // often, but older files allowed it and may still exist.
     211               0 :     for( i = 0; i < nPairs; i++ )
     212                 :     {
     213               0 :         if( anUsgsEsriZones[i*2+1] == nITTVISZone )
     214               0 :             return anUsgsEsriZones[i*2];
     215                 :     }
     216                 : 
     217               0 :     return nITTVISZone; // perhaps it *is* the USGS zone?
     218                 : }
     219                 : 
     220                 : /************************************************************************/
     221                 : /* ==================================================================== */
     222                 : /*                              ENVIDataset                             */
     223                 : /* ==================================================================== */
     224                 : /************************************************************************/
     225                 : 
     226                 : class ENVIRasterBand;
     227                 : 
     228                 : class ENVIDataset : public RawDataset
     229                 : {
     230                 :     friend class ENVIRasterBand;
     231                 : 
     232                 :     VSILFILE  *fpImage; // image data file.
     233                 :     VSILFILE  *fp;    // header file
     234                 :     char  *pszHDRFilename;
     235                 : 
     236                 :     int   bFoundMapinfo;
     237                 : 
     238                 :     int         bHeaderDirty;
     239                 : 
     240                 :     double      adfGeoTransform[6];
     241                 : 
     242                 :     char  *pszProjection;
     243                 : 
     244                 :     char        **papszHeader;
     245                 : 
     246                 :     CPLString   osStaFilename;
     247                 : 
     248                 :     int         ReadHeader( VSILFILE * );
     249                 :     int         ProcessMapinfo( const char * );
     250                 :     void        ProcessRPCinfo( const char * ,int ,int);
     251                 :     void        ProcessStatsFile();
     252                 :     int         byteSwapInt(int);
     253                 :     float       byteSwapFloat(float);
     254                 :     double      byteSwapDouble(double);
     255                 :     void        SetENVIDatum( OGRSpatialReference *, const char * );
     256                 :     void        SetENVIEllipse( OGRSpatialReference *, char ** );
     257                 :     void        WriteProjectionInfo();
     258                 :     int         ParseRpcCoeffsMetaDataString(const char *psName, char *papszVal[], int& idx);
     259                 :     int         WriteRpcInfo();
     260                 :     int         WritePseudoGcpInfo();
     261                 :     
     262                 :     char        **SplitList( const char * );
     263                 : 
     264                 :     enum Interleave { BSQ, BIL, BIP } interleave;
     265                 :     static int GetEnviType(GDALDataType eType);
     266                 : 
     267                 :   public:
     268                 :             ENVIDataset();
     269                 :             ~ENVIDataset();
     270                 : 
     271                 :     virtual void    FlushCache( void );
     272                 :     virtual CPLErr  GetGeoTransform( double * padfTransform );
     273                 :     virtual CPLErr  SetGeoTransform( double * );
     274                 :     virtual const char *GetProjectionRef(void);
     275                 :     virtual CPLErr  SetProjection( const char * );
     276                 :     virtual char  **GetFileList(void);
     277                 :     
     278                 :     virtual void        SetDescription( const char * );
     279                 : 
     280                 :     virtual CPLErr      SetMetadata( char ** papszMetadata,
     281                 :                                      const char * pszDomain = "" );
     282                 :     virtual CPLErr      SetMetadataItem( const char * pszName,
     283                 :                                          const char * pszValue,
     284                 :                                          const char * pszDomain = "" );
     285                 :     virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
     286                 :                             const char *pszGCPProjection );
     287                 : 
     288                 :     static GDALDataset *Open( GDALOpenInfo * );
     289                 :     static GDALDataset *Create( const char * pszFilename,
     290                 :                                 int nXSize, int nYSize, int nBands,
     291                 :                                 GDALDataType eType, char ** papszOptions );
     292                 : };
     293                 : 
     294                 : /************************************************************************/
     295                 : /* ==================================================================== */
     296                 : /*                            ENVIRasterBand                            */
     297                 : /* ==================================================================== */
     298                 : /************************************************************************/
     299                 : 
     300                 : class ENVIRasterBand : public RawRasterBand
     301             189 : {
     302                 :     public:
     303                 :                 ENVIRasterBand( GDALDataset *poDS, int nBand, void * fpRaw,
     304                 :                                 vsi_l_offset nImgOffset, int nPixelOffset,
     305                 :                                 int nLineOffset,
     306                 :                                 GDALDataType eDataType, int bNativeOrder,
     307                 :                                 int bIsVSIL = FALSE, int bOwnsFP = FALSE );
     308                 : 
     309                 :     virtual void        SetDescription( const char * );
     310                 : 
     311                 :     virtual CPLErr SetCategoryNames( char ** );
     312                 : };
     313                 : 
     314                 : /************************************************************************/
     315                 : /*                            ENVIDataset()                             */
     316                 : /************************************************************************/
     317                 : 
     318             116 : ENVIDataset::ENVIDataset()
     319                 : {
     320             116 :     fpImage = NULL;
     321             116 :     fp = NULL;
     322             116 :     pszHDRFilename = NULL;
     323             116 :     pszProjection = CPLStrdup("");
     324                 : 
     325             116 :     papszHeader = NULL;
     326                 : 
     327             116 :     bFoundMapinfo = FALSE;
     328                 : 
     329             116 :     bHeaderDirty = FALSE;
     330                 : 
     331             116 :     adfGeoTransform[0] = 0.0;
     332             116 :     adfGeoTransform[1] = 1.0;
     333             116 :     adfGeoTransform[2] = 0.0;
     334             116 :     adfGeoTransform[3] = 0.0;
     335             116 :     adfGeoTransform[4] = 0.0;
     336             116 :     adfGeoTransform[5] = 1.0;
     337             116 : }
     338                 : 
     339                 : /************************************************************************/
     340                 : /*                            ~ENVIDataset()                            */
     341                 : /************************************************************************/
     342                 : 
     343             116 : ENVIDataset::~ENVIDataset()
     344                 : 
     345                 : {
     346             116 :     FlushCache();
     347             116 :     if( fpImage )
     348             114 :         VSIFCloseL( fpImage );
     349             116 :     if( fp )
     350             116 :         VSIFCloseL( fp );
     351             116 :     CPLFree( pszProjection );
     352             116 :     CSLDestroy( papszHeader );
     353             116 :     CPLFree(pszHDRFilename);
     354             116 : }
     355                 : 
     356                 : /************************************************************************/
     357                 : /*                             FlushCache()                             */
     358                 : /************************************************************************/
     359                 : 
     360             116 : void ENVIDataset::FlushCache()
     361                 : 
     362                 : {
     363             116 :     RawDataset::FlushCache();
     364                 : 
     365             116 :     GDALRasterBand* band = (GetRasterCount() > 0) ? GetRasterBand(1) : NULL;
     366                 : 
     367             116 :     if ( band == NULL || !bHeaderDirty )
     368               2 :         return;
     369                 : 
     370             114 :     CPLLocaleC  oLocaleEnforcer;
     371                 : 
     372             114 :     VSIFSeekL( fp, 0, SEEK_SET );
     373                 : /* -------------------------------------------------------------------- */
     374                 : /*      Rewrite out the header.                                           */
     375                 : /* -------------------------------------------------------------------- */
     376                 :     int   iBigEndian;
     377                 : 
     378                 :     const char  *pszInterleaving;
     379                 :     char** catNames;
     380                 : 
     381                 : #ifdef CPL_LSB
     382             114 :     iBigEndian = 0;
     383                 : #else
     384                 :     iBigEndian = 1;
     385                 : #endif
     386                 : 
     387             114 :     VSIFPrintfL( fp, "ENVI\n" );
     388             114 :     if ("" != sDescription)
     389             114 :         VSIFPrintfL( fp, "description = {\n%s}\n", sDescription.c_str());
     390                 :     VSIFPrintfL( fp, "samples = %d\nlines   = %d\nbands   = %d\n",
     391             114 :     nRasterXSize, nRasterYSize, nBands );
     392                 : 
     393             114 :     catNames = band->GetCategoryNames();
     394                 : 
     395             114 :     VSIFPrintfL( fp, "header offset = 0\n");
     396             114 :     if (0 == catNames)
     397             110 :         VSIFPrintfL( fp, "file type = ENVI Standard\n" );
     398                 :     else
     399               4 :         VSIFPrintfL( fp, "file type = ENVI Classification\n" );
     400                 : 
     401             114 :     int iENVIType = GetEnviType(band->GetRasterDataType());
     402             114 :     VSIFPrintfL( fp, "data type = %d\n", iENVIType );
     403             114 :     switch (interleave)
     404                 :     {
     405                 :       case BIP:
     406               0 :         pszInterleaving = "bip";        // interleaved by pixel
     407               0 :         break;
     408                 :       case BIL:
     409               0 :         pszInterleaving = "bil";        // interleaved by line
     410               0 :         break;
     411                 :       case BSQ:
     412             114 :         pszInterleaving = "bsq";    // band sequental by default
     413             114 :         break;
     414                 :       default:
     415               0 :       pszInterleaving = "bsq";
     416                 :         break;
     417                 :     }
     418             114 :     VSIFPrintfL( fp, "interleave = %s\n", pszInterleaving);
     419             114 :     VSIFPrintfL( fp, "byte order = %d\n", iBigEndian );
     420                 : 
     421                 : /* -------------------------------------------------------------------- */
     422                 : /*      Write class and color information                               */
     423                 : /* -------------------------------------------------------------------- */
     424             114 :     catNames = band->GetCategoryNames();
     425             114 :     if (0 != catNames)
     426                 :     {
     427               4 :         int nrClasses = 0;
     428              16 :         while (*catNames++)
     429               8 :             ++nrClasses;
     430                 : 
     431               4 :         if (nrClasses > 0)
     432                 :         {
     433               4 :             VSIFPrintfL( fp, "classes = %d\n", nrClasses );
     434                 : 
     435               4 :             GDALColorTable* colorTable = band->GetColorTable();
     436               4 :             if (0 != colorTable)
     437                 :             {
     438               4 :                 int nrColors = colorTable->GetColorEntryCount();
     439               4 :                 if (nrColors > nrClasses)
     440               0 :                     nrColors = nrClasses;
     441               4 :                 VSIFPrintfL( fp, "class lookup = {\n");
     442              12 :                 for (int i = 0; i < nrColors; ++i)
     443                 :                 {
     444               8 :                     const GDALColorEntry* color = colorTable->GetColorEntry(i);
     445               8 :                     VSIFPrintfL(fp, "%d, %d, %d", color->c1, color->c2, color->c3);
     446               8 :                     if (i < nrColors - 1)
     447                 :                     {
     448               4 :                         VSIFPrintfL(fp, ", ");
     449               4 :                         if (0 == (i+1) % 5)
     450               0 :                             VSIFPrintfL(fp, "\n");
     451                 :                     }
     452                 :                 }
     453               4 :                 VSIFPrintfL(fp, "}\n");
     454                 :             }
     455                 : 
     456               4 :             catNames = band->GetCategoryNames();
     457               4 :             if (0 != *catNames)
     458                 :             {
     459               4 :                 VSIFPrintfL( fp, "class names = {\n%s", *catNames++);
     460               4 :                 int i = 0;
     461              12 :                 while (*catNames) {
     462               4 :                     VSIFPrintfL( fp, ",");
     463               4 :                     if (0 == (++i) % 5)
     464               0 :                         VSIFPrintfL(fp, "\n");
     465               4 :                     VSIFPrintfL( fp, " %s", *catNames++);
     466                 :                 }
     467               4 :                 VSIFPrintfL( fp, "}\n");
     468                 :             }
     469                 :         }
     470                 :     }
     471                 : 
     472                 : /* -------------------------------------------------------------------- */
     473                 : /*      Write the rest of header.                                       */
     474                 : /* -------------------------------------------------------------------- */
     475                 :     
     476                 :     // only one map info type should be set
     477                 :     //     - rpc
     478                 :     //     - pseudo/gcp 
     479                 :     //     - standard
     480             114 :     if ( !WriteRpcInfo() ) // are rpcs in the metadata
     481                 :     {
     482             110 :         if ( !WritePseudoGcpInfo() ) // are gcps in the metadata
     483                 :         {
     484             110 :             WriteProjectionInfo(); // standard - affine xform/coord sys str
     485                 :         }
     486                 :     }
     487                 : 
     488                 : 
     489             114 :     VSIFPrintfL( fp, "band names = {\n" );
     490             303 :     for ( int i = 1; i <= nBands; i++ )
     491                 :     {
     492             189 :         CPLString sBandDesc = GetRasterBand( i )->GetDescription();
     493                 : 
     494             189 :         if ( sBandDesc == "" )
     495              92 :             sBandDesc = CPLSPrintf( "Band %d", i );
     496             189 :         VSIFPrintfL( fp, "%s", sBandDesc.c_str() );
     497             189 :         if ( i != nBands )
     498              75 :             VSIFPrintfL( fp, ",\n" );
     499                 :     }
     500             114 :     VSIFPrintfL( fp, "}\n" );
     501                 : 
     502                 : /* -------------------------------------------------------------------- */
     503                 : /*      Write the metadata that was read into the ENVI domain           */
     504                 : /* -------------------------------------------------------------------- */
     505             114 :     char** papszENVIMetadata = GetMetadata("ENVI");
     506                 : 
     507                 :     int i;
     508             114 :     int count = CSLCount(papszENVIMetadata);
     509                 :     char **papszTokens;
     510                 : 
     511                 :     // For every item of metadata in the ENVI domain
     512             114 :     for (i = 0; i < count; i++)
     513                 :     {
     514                 :         // Split the entry into two parts at the = character
     515            1154 :         char *pszEntry = papszENVIMetadata[i];
     516            1154 :         papszTokens = CSLTokenizeString2( pszEntry, "=", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
     517                 : 
     518            1154 :         if (CSLCount(papszTokens) != 2)
     519                 :         {
     520               1 :             CPLDebug("ENVI", "Line of header file could not be split at = into two elements: %s", papszENVIMetadata[i]);
     521               1 :             CSLDestroy( papszTokens );
     522               1 :             continue;
     523                 :         }
     524                 :         // Replace _'s in the string with spaces
     525            1153 :         std::string poKey(papszTokens[0]);
     526            2306 :         std::replace(poKey.begin(), poKey.end(), '_', ' ');
     527                 : 
     528                 :         // Don't write it out if it is one of the bits of metadata that is written out elsewhere in this routine
     529            1153 :         if (poKey == "description" || poKey == "samples" || poKey == "lines" ||
     530                 :             poKey == "bands" || poKey == "header offset" || poKey == "file type" ||
     531                 :             poKey == "data type" || poKey == "interleave" || poKey == "byte order" ||
     532                 :             poKey == "class names" || poKey == "band names" || poKey == "map info" ||
     533                 :             poKey == "projection info")
     534                 :         {
     535            1096 :             CSLDestroy( papszTokens );
     536            1096 :             continue;
     537                 :         }
     538              57 :         VSIFPrintfL( fp, "%s = %s\n", poKey.c_str(), papszTokens[1]);
     539              57 :         CSLDestroy( papszTokens );
     540                 :     }
     541                 : 
     542                 :     /* Clean dirty flag */
     543             114 :     bHeaderDirty = FALSE;
     544                 : }
     545                 : 
     546                 : /************************************************************************/
     547                 : /*                            GetFileList()                             */
     548                 : /************************************************************************/
     549                 :      
     550              11 : char **ENVIDataset::GetFileList() 
     551                 :     
     552                 : { 
     553              11 :     char **papszFileList = NULL; 
     554                 :     
     555                 :     // Main data file, etc.  
     556              11 :     papszFileList = RawDataset::GetFileList(); 
     557                 :     
     558                 :     // Header file. 
     559              11 :     papszFileList = CSLAddString( papszFileList, pszHDRFilename );
     560                 : 
     561                 :     // Statistics file
     562              11 :     if (osStaFilename.size() != 0)
     563               0 :         papszFileList = CSLAddString( papszFileList, osStaFilename );
     564                 :     
     565              11 :     return papszFileList; 
     566                 : }
     567                 : 
     568                 : /************************************************************************/
     569                 : /*                           GetEPSGGeogCS()                            */
     570                 : /*                                                                      */
     571                 : /*      Try to establish what the EPSG code for this coordinate         */
     572                 : /*      systems GEOGCS might be.  Returns -1 if no reasonable guess     */
     573                 : /*      can be made.                                                    */
     574                 : /*                                                                      */
     575                 : /*      TODO: We really need to do some name lookups.                   */
     576                 : /************************************************************************/
     577                 : 
     578              98 : static int ENVIGetEPSGGeogCS( OGRSpatialReference *poThis )
     579                 : 
     580                 : {
     581              98 :     const char *pszAuthName = poThis->GetAuthorityName( "GEOGCS" );
     582                 : 
     583                 : /* -------------------------------------------------------------------- */
     584                 : /*      Do we already have it?                                          */
     585                 : /* -------------------------------------------------------------------- */
     586              98 :     if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
     587              23 :         return atoi(poThis->GetAuthorityCode( "GEOGCS" ));
     588                 : 
     589                 : /* -------------------------------------------------------------------- */
     590                 : /*      Get the datum and geogcs names.                                 */
     591                 : /* -------------------------------------------------------------------- */
     592              75 :     const char *pszGEOGCS = poThis->GetAttrValue( "GEOGCS" );
     593              75 :     const char *pszDatum = poThis->GetAttrValue( "DATUM" );
     594                 : 
     595                 :     // We can only operate on coordinate systems with a geogcs.
     596              75 :     if( pszGEOGCS == NULL || pszDatum == NULL )
     597               1 :         return -1;
     598                 : 
     599                 : /* -------------------------------------------------------------------- */
     600                 : /*      Is this a "well known" geographic coordinate system?            */
     601                 : /* -------------------------------------------------------------------- */
     602                 :     int bWGS, bNAD;
     603                 : 
     604                 :     bWGS = strstr(pszGEOGCS,"WGS") != NULL
     605                 :         || strstr(pszDatum, "WGS")
     606                 :         || strstr(pszGEOGCS,"World Geodetic System")
     607                 :         || strstr(pszGEOGCS,"World_Geodetic_System")
     608                 :         || strstr(pszDatum, "World Geodetic System")
     609              74 :         || strstr(pszDatum, "World_Geodetic_System"); 
     610                 : 
     611                 :     bNAD = strstr(pszGEOGCS,"NAD") != NULL
     612                 :         || strstr(pszDatum, "NAD")
     613                 :         || strstr(pszGEOGCS,"North American")
     614                 :         || strstr(pszGEOGCS,"North_American")
     615                 :         || strstr(pszDatum, "North American")
     616              74 :         || strstr(pszDatum, "North_American"); 
     617                 : 
     618              74 :     if( bWGS && (strstr(pszGEOGCS,"84") || strstr(pszDatum,"84")) )
     619              50 :         return 4326;
     620                 : 
     621              24 :     if( bWGS && (strstr(pszGEOGCS,"72") || strstr(pszDatum,"72")) )
     622               0 :         return 4322;
     623                 : 
     624              24 :     if( bNAD && (strstr(pszGEOGCS,"83") || strstr(pszDatum,"83")) )
     625               3 :         return 4269;
     626                 : 
     627              21 :     if( bNAD && (strstr(pszGEOGCS,"27") || strstr(pszDatum,"27")) )
     628               0 :         return 4267;
     629                 : 
     630                 : /* -------------------------------------------------------------------- */
     631                 : /*      If we know the datum, associate the most likely GCS with        */
     632                 : /*      it.                                                             */
     633                 : /* -------------------------------------------------------------------- */
     634              21 :     pszAuthName = poThis->GetAuthorityName( "GEOGCS|DATUM" );
     635                 : 
     636              21 :     if( pszAuthName != NULL 
     637                 :         && EQUAL(pszAuthName,"epsg") 
     638                 :         && poThis->GetPrimeMeridian() == 0.0 )
     639                 :     {
     640               0 :         int nDatum = atoi(poThis->GetAuthorityCode("GEOGCS|DATUM"));
     641                 :         
     642               0 :         if( nDatum >= 6000 && nDatum <= 6999 )
     643               0 :             return nDatum - 2000;
     644                 :     }
     645                 : 
     646              21 :     return -1;
     647                 : }
     648                 : 
     649                 : /************************************************************************/
     650                 : /*                        WriteProjectionInfo()                         */
     651                 : /************************************************************************/
     652                 : 
     653             110 : void ENVIDataset::WriteProjectionInfo()
     654                 : 
     655                 : {
     656                 : /* -------------------------------------------------------------------- */
     657                 : /*      Format the location (geotransform) portion of the map info      */
     658                 : /*      line.                                                           */
     659                 : /* -------------------------------------------------------------------- */
     660             110 :     CPLString   osLocation;
     661                 : 
     662                 :     osLocation.Printf( "1, 1, %.15g, %.15g, %.15g, %.15g", 
     663                 :                        adfGeoTransform[0], adfGeoTransform[3], 
     664             110 :                        adfGeoTransform[1], fabs(adfGeoTransform[5]) );
     665                 :                        
     666                 : /* -------------------------------------------------------------------- */
     667                 : /*      Minimal case - write out simple geotransform if we have a       */
     668                 : /*      non-default geotransform.                                       */
     669                 : /* -------------------------------------------------------------------- */
     670             110 :     if( pszProjection == NULL || strlen(pszProjection) == 0 )
     671                 :     {
     672              56 :         if( adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
     673              22 :             || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
     674              22 :             || adfGeoTransform[4] != 0.0 || adfGeoTransform[5] != 1.0 )
     675                 :         {
     676               1 :             const char* pszHemisphere = "North";
     677                 :             VSIFPrintfL( fp, "map info = {Unknown, %s, %d, %s}\n",
     678               1 :                          osLocation.c_str(), 0, pszHemisphere);
     679                 :         }
     680                 :         return;
     681                 :     }
     682                 : 
     683                 : /* -------------------------------------------------------------------- */
     684                 : /*      Ingest WKT.                                                     */
     685                 : /* -------------------------------------------------------------------- */
     686              98 :     OGRSpatialReference oSRS;
     687                 :     
     688              98 :     char  *pszProj = pszProjection;
     689                 :     
     690              98 :     if( oSRS.importFromWkt( &pszProj ) != OGRERR_NONE )
     691                 :         return;
     692                 : 
     693                 : /* -------------------------------------------------------------------- */
     694                 : /*      Try to translate the datum and get major/minor ellipsoid        */
     695                 : /*      values.                                                         */
     696                 : /* -------------------------------------------------------------------- */
     697              98 :     int nEPSG_GCS = ENVIGetEPSGGeogCS( &oSRS );
     698              98 :     CPLString osDatum, osCommaDatum;
     699                 :     double dfA, dfB;
     700                 : 
     701              98 :     if( nEPSG_GCS == 4326 )
     702              65 :         osDatum = "WGS-84";
     703              33 :     else if( nEPSG_GCS == 4322 )
     704               0 :         osDatum = "WGS-72";
     705              33 :     else if( nEPSG_GCS == 4269 )
     706               3 :         osDatum = "North America 1983";
     707              30 :     else if( nEPSG_GCS == 4267 )
     708               7 :         osDatum = "North America 1927";
     709              23 :     else if( nEPSG_GCS == 4230 )
     710               0 :         osDatum = "European 1950";
     711              23 :     else if( nEPSG_GCS == 4277 )
     712               1 :         osDatum = "Ordnance Survey of Great Britain '36";
     713              22 :     else if( nEPSG_GCS == 4291 )
     714               0 :         osDatum = "SAD-69/Brazil";
     715              22 :     else if( nEPSG_GCS == 4283 )
     716               0 :         osDatum = "Geocentric Datum of Australia 1994";
     717              22 :     else if( nEPSG_GCS == 4275 )
     718               0 :         osDatum = "Nouvelle Triangulation Francaise IGN";
     719                 : 
     720              98 :     if( osDatum != "" )
     721              76 :         osCommaDatum.Printf( ",%s", osDatum.c_str() );
     722                 : 
     723              98 :     dfA = oSRS.GetSemiMajor();
     724              98 :     dfB = oSRS.GetSemiMinor();
     725                 : 
     726                 : /* -------------------------------------------------------------------- */
     727                 : /*      Do we have unusual linear units?                                */
     728                 : /* -------------------------------------------------------------------- */
     729              98 :     CPLString osOptionalUnits;
     730              98 :     if( fabs(oSRS.GetLinearUnits()-0.3048) < 0.0001 )
     731               0 :         osOptionalUnits = ", units=Feet";
     732                 : 
     733                 : /* -------------------------------------------------------------------- */
     734                 : /*      Handle UTM case.                                                */
     735                 : /* -------------------------------------------------------------------- */
     736                 :     const char  *pszHemisphere;
     737              98 :     const char  *pszProjName = oSRS.GetAttrValue("PROJECTION");
     738                 :     int   bNorth;
     739                 :     int   iUTMZone;
     740                 : 
     741              98 :     iUTMZone = oSRS.GetUTMZone( &bNorth );
     742              98 :     if ( iUTMZone )
     743                 :     {
     744               7 :         if ( bNorth )
     745               7 :             pszHemisphere = "North";
     746                 :         else
     747               0 :             pszHemisphere = "South";
     748                 : 
     749                 :         VSIFPrintfL( fp, "map info = {UTM, %s, %d, %s%s%s}\n",
     750                 :                      osLocation.c_str(), iUTMZone, pszHemisphere,
     751               7 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     752                 :     }
     753              91 :     else if( oSRS.IsGeographic() )
     754                 :     {
     755                 :         VSIFPrintfL( fp, "map info = {Geographic Lat/Lon, %s%s}\n",
     756              65 :                      osLocation.c_str(), osCommaDatum.c_str());
     757                 :     }
     758              26 :     else if( pszProjName == NULL )
     759                 :     {
     760                 :         // what to do? 
     761                 :     }
     762              25 :     else if( EQUAL(pszProjName,SRS_PT_NEW_ZEALAND_MAP_GRID) )
     763                 :     {
     764                 :         VSIFPrintfL( fp, "map info = {New Zealand Map Grid, %s%s%s}\n",
     765                 :                      osLocation.c_str(), 
     766               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     767                 : 
     768                 :         VSIFPrintfL( fp, "projection info = {39, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, New Zealand Map Grid}\n",
     769                 :                      dfA, dfB, 
     770                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     771                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     772                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     773                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     774               0 :                      osCommaDatum.c_str() );
     775                 :     }
     776              25 :     else if( EQUAL(pszProjName,SRS_PT_TRANSVERSE_MERCATOR) )
     777                 :     {
     778                 :         VSIFPrintfL( fp, "map info = {Transverse Mercator, %s%s%s}\n",
     779                 :                      osLocation.c_str(), 
     780               3 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     781                 : 
     782                 :         VSIFPrintfL( fp, "projection info = {3, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Transverse Mercator}\n",
     783                 :                      dfA, dfB, 
     784                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     785                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     786                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     787                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     788                 :                      oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0),
     789               3 :                      osCommaDatum.c_str() );
     790                 :     }
     791              25 :     else if( EQUAL(pszProjName,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP)
     792                 :              || EQUAL(pszProjName,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM) )
     793                 :     {
     794                 :         VSIFPrintfL( fp, "map info = {Lambert Conformal Conic, %s%s%s}\n",
     795                 :                      osLocation.c_str(), 
     796               3 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     797                 : 
     798                 :         VSIFPrintfL( fp, "projection info = {4, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Lambert Conformal Conic}\n",
     799                 :                      dfA, dfB, 
     800                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     801                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     802                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     803                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     804                 :                      oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
     805                 :                      oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0),
     806               3 :                      osCommaDatum.c_str() );
     807                 :     }
     808              19 :     else if( EQUAL(pszProjName,
     809                 :                    SRS_PT_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN) )
     810                 :     {
     811                 :         VSIFPrintfL( fp, "map info = {Hotine Oblique Mercator A, %s%s%s}\n",
     812                 :                      osLocation.c_str(), 
     813               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     814                 : 
     815                 :         VSIFPrintfL( fp, "projection info = {5, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Hotine Oblique Mercator A}\n",
     816                 :                      dfA, dfB, 
     817                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     818                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_1,0.0),
     819                 :                      oSRS.GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_1,0.0),
     820                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_2,0.0),
     821                 :                      oSRS.GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_2,0.0),
     822                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     823                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     824                 :                      oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0),
     825               0 :                      osCommaDatum.c_str() );
     826                 :     }
     827              19 :     else if( EQUAL(pszProjName,SRS_PT_HOTINE_OBLIQUE_MERCATOR) )
     828                 :     {
     829                 :         VSIFPrintfL( fp, "map info = {Hotine Oblique Mercator B, %s%s%s}\n",
     830                 :                      osLocation.c_str(), 
     831               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     832                 : 
     833                 :         VSIFPrintfL( fp, "projection info = {6, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Hotine Oblique Mercator B}\n",
     834                 :                      dfA, dfB, 
     835                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     836                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     837                 :                      oSRS.GetNormProjParm(SRS_PP_AZIMUTH,0.0),
     838                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     839                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     840                 :                      oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0),
     841               0 :                      osCommaDatum.c_str() );
     842                 :     }
     843              19 :     else if( EQUAL(pszProjName,SRS_PT_STEREOGRAPHIC) 
     844                 :              || EQUAL(pszProjName,SRS_PT_OBLIQUE_STEREOGRAPHIC) )
     845                 :     {
     846                 :         VSIFPrintfL( fp, "map info = {Stereographic (ellipsoid), %s%s%s}\n",
     847                 :                      osLocation.c_str(), 
     848               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     849                 : 
     850                 :         VSIFPrintfL( fp, "projection info = {7, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %s, Stereographic (ellipsoid)}\n",
     851                 :                      dfA, dfB, 
     852                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     853                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     854                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     855                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     856                 :                      oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0),
     857               0 :                      osCommaDatum.c_str() );
     858                 :     }
     859              19 :     else if( EQUAL(pszProjName,SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
     860                 :     {
     861                 :         VSIFPrintfL( fp, "map info = {Albers Conical Equal Area, %s%s%s}\n",
     862                 :                      osLocation.c_str(), 
     863              16 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     864                 : 
     865                 :         VSIFPrintfL( fp, "projection info = {9, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Albers Conical Equal Area}\n",
     866                 :                      dfA, dfB, 
     867                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     868                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     869                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     870                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     871                 :                      oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
     872                 :                      oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0),
     873              16 :                      osCommaDatum.c_str() );
     874                 :     }
     875               3 :     else if( EQUAL(pszProjName,SRS_PT_POLYCONIC) )
     876                 :     {
     877                 :         VSIFPrintfL( fp, "map info = {Polyconic, %s%s%s}\n",
     878                 :                      osLocation.c_str(), 
     879               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     880                 : 
     881                 :         VSIFPrintfL( fp, "projection info = {10, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Polyconic}\n",
     882                 :                      dfA, dfB, 
     883                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     884                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     885                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     886                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     887               0 :                      osCommaDatum.c_str() );
     888                 :     }
     889               3 :     else if( EQUAL(pszProjName,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
     890                 :     {
     891                 :         VSIFPrintfL( fp, "map info = {Lambert Azimuthal Equal Area, %s%s%s}\n",
     892                 :                      osLocation.c_str(), 
     893               3 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     894                 : 
     895                 :         VSIFPrintfL( fp, "projection info = {11, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Lambert Azimuthal Equal Area}\n",
     896                 :                      dfA, dfB, 
     897                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     898                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     899                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     900                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     901               3 :                      osCommaDatum.c_str() );
     902                 :     }
     903               0 :     else if( EQUAL(pszProjName,SRS_PT_AZIMUTHAL_EQUIDISTANT) )
     904                 :     {
     905                 :         VSIFPrintfL( fp, "map info = {Azimuthal Equadistant, %s%s%s}\n",
     906                 :                      osLocation.c_str(), 
     907               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     908                 : 
     909                 :         VSIFPrintfL( fp, "projection info = {12, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Azimuthal Equadistant}\n",
     910                 :                      dfA, dfB, 
     911                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
     912                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     913                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     914                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     915               0 :                      osCommaDatum.c_str() );
     916                 :     }
     917               0 :     else if( EQUAL(pszProjName,SRS_PT_POLAR_STEREOGRAPHIC) )
     918                 :     {
     919                 :         VSIFPrintfL( fp, "map info = {Polar Stereographic, %s%s%s}\n",
     920                 :                      osLocation.c_str(), 
     921               0 :                      osCommaDatum.c_str(), osOptionalUnits.c_str() );
     922                 : 
     923                 :         VSIFPrintfL( fp, "projection info = {31, %.16g, %.16g, %.16g, %.16g, %.16g, %.16g%s, Polar Stereographic}\n",
     924                 :                      dfA, dfB, 
     925                 :                      oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,90.0),
     926                 :                      oSRS.GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
     927                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
     928                 :                      oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
     929               0 :                      osCommaDatum.c_str() );
     930                 :     }
     931                 :     else
     932                 :     {
     933                 :         VSIFPrintfL( fp, "map info = {%s, %s}\n",
     934               0 :                      pszProjName, osLocation.c_str());
     935                 :     }
     936                 : 
     937                 :     // write out coordinate system string
     938              98 :     if ( oSRS.morphToESRI() == OGRERR_NONE )
     939                 :     {
     940              98 :         char *pszProjESRI = NULL;
     941              98 :         if ( oSRS.exportToWkt(&pszProjESRI) == OGRERR_NONE )
     942                 :         {
     943              98 :             if ( strlen(pszProjESRI) )
     944              97 :                 VSIFPrintfL( fp, "coordinate system string = {%s}\n", pszProjESRI);
     945                 :         }
     946              98 :         CPLFree(pszProjESRI);
     947              98 :         pszProjESRI = NULL;
     948              98 :     }
     949                 : }
     950                 : 
     951                 : /************************************************************************/
     952                 : /*                ParseRpcCoeffsMetaDataString()                        */
     953                 : /************************************************************************/
     954                 : 
     955              16 : int ENVIDataset::ParseRpcCoeffsMetaDataString(const char *psName, char **papszVal,
     956                 :                                               int& idx)
     957                 : {
     958                 :     // separate one string with 20 coefficients into an array of 20 strings.
     959              16 :     const char *psz20Vals = GetMetadataItem(psName, "RPC");
     960              16 :     if (!psz20Vals)
     961               0 :         return FALSE;
     962                 : 
     963              16 :     char** papszArr = CSLTokenizeString2(psz20Vals, " ", 0);
     964              16 :     if (!papszArr)
     965               0 :         return FALSE;
     966                 : 
     967              16 :     int x = 0;
     968             352 :     while ((papszArr[x] != NULL) && (x < 20))
     969                 :     {
     970             320 :         papszVal[idx++] = CPLStrdup(papszArr[x]);
     971             320 :         x++;
     972                 :     }
     973                 : 
     974              16 :     CSLDestroy(papszArr);
     975                 : 
     976              16 :     return (x == 20);
     977                 : }
     978                 : 
     979                 : #define CPLStrdupIfNotNull(x) ((x) ? CPLStrdup(x) : NULL)
     980                 : 
     981                 : /************************************************************************/
     982                 : /*                          WriteRpcInfo()                              */
     983                 : /************************************************************************/
     984                 : 
     985             114 : int ENVIDataset::WriteRpcInfo()
     986                 : {
     987                 :     // write out 90 rpc coeffs into the envi header plus 3 envi specific rpc values
     988                 :     // returns 0 if the coeffs are not present or not valid
     989             114 :     int bRet = FALSE;
     990             114 :     int x, idx = 0;
     991                 :     char* papszVal[93];
     992                 : 
     993             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("LINE_OFF", "RPC"));
     994             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("SAMP_OFF", "RPC"));
     995             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("LAT_OFF", "RPC"));
     996             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("LONG_OFF", "RPC"));
     997             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("HEIGHT_OFF", "RPC"));
     998             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("LINE_SCALE", "RPC"));
     999             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("SAMP_SCALE", "RPC"));
    1000             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("LAT_SCALE", "RPC"));
    1001             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("LONG_SCALE", "RPC"));
    1002             114 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("HEIGHT_SCALE", "RPC"));
    1003                 : 
    1004             154 :     for (x=0; x<10; x++) // if we do not have 10 values we return 0
    1005                 :     {
    1006             150 :         if (!papszVal[x])
    1007             110 :             goto end;
    1008                 :     }
    1009                 : 
    1010               4 :     if (!ParseRpcCoeffsMetaDataString("LINE_NUM_COEFF", papszVal, idx))
    1011               0 :         goto end;
    1012                 : 
    1013               4 :     if (!ParseRpcCoeffsMetaDataString("LINE_DEN_COEFF", papszVal, idx))
    1014               0 :         goto end;
    1015                 : 
    1016               4 :     if (!ParseRpcCoeffsMetaDataString("SAMP_NUM_COEFF", papszVal, idx))
    1017               0 :         goto end;
    1018                 : 
    1019               4 :     if (!ParseRpcCoeffsMetaDataString("SAMP_DEN_COEFF", papszVal, idx))
    1020               0 :         goto end;
    1021                 : 
    1022               4 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("TILE_ROW_OFFSET", "RPC"));
    1023               4 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("TILE_COL_OFFSET", "RPC"));
    1024               4 :     papszVal[idx++] = CPLStrdupIfNotNull(GetMetadataItem("ENVI_RPC_EMULATION", "RPC"));
    1025               4 :     CPLAssert(idx == 93);
    1026              16 :     for (x=90; x<93; x++)
    1027                 :     {
    1028              12 :         if (!papszVal[x])
    1029               0 :             goto end;
    1030                 :     }
    1031                 : 
    1032                 :     // ok all the needed 93 values are present so write the rpcs into the envi header
    1033               4 :     x = 1;
    1034               4 :     VSIFPrintfL(fp, "rpc info = {\n");
    1035             376 :     for (int iR=0; iR<93; iR++)
    1036                 :     {
    1037             372 :       if (papszVal[iR][0] == '-')
    1038              32 :         VSIFPrintfL(fp, " %s", papszVal[iR]);
    1039                 :       else
    1040             340 :         VSIFPrintfL(fp, "  %s", papszVal[iR]);
    1041                 :       
    1042             372 :       if (iR<92)
    1043             368 :         VSIFPrintfL(fp, ",");
    1044                 : 
    1045             372 :       if ((x % 4) == 0)
    1046              92 :           VSIFPrintfL(fp, "\n");
    1047                 :      
    1048             372 :       x++;
    1049             372 :       if (x > 4) 
    1050              92 :         x = 1;
    1051                 :     }
    1052                 : 
    1053               4 :     VSIFPrintfL(fp, "}\n" );
    1054                 : 
    1055               4 :     bRet = TRUE;
    1056                 : 
    1057                 : end:
    1058            1586 :     for (x=0;x<idx;x++)
    1059            1472 :         CPLFree(papszVal[x]);
    1060                 : 
    1061             114 :     return bRet;
    1062                 : }
    1063                 : 
    1064                 : /************************************************************************/
    1065                 : /*                        WritePseudoGcpInfo()                          */
    1066                 : /************************************************************************/
    1067                 : 
    1068             110 : int ENVIDataset::WritePseudoGcpInfo()
    1069                 : {
    1070                 :     // write out gcps into the envi header
    1071                 :     // returns 0 if the gcps are not present
    1072                 : 
    1073             110 :     int iNum = GetGCPCount();
    1074             110 :     if (iNum == 0)
    1075             110 :       return FALSE;
    1076                 : 
    1077               0 :     const GDAL_GCP *pGcpStructs = GetGCPs();
    1078                 : 
    1079                 :     //    double      dfGCPPixel; /** Pixel (x) location of GCP on raster */
    1080                 :     //    double      dfGCPLine;  /** Line (y) location of GCP on raster */
    1081                 :     //    double      dfGCPX;     /** X position of GCP in georeferenced space */
    1082                 :     //    double      dfGCPY;     /** Y position of GCP in georeferenced space */
    1083                 : 
    1084               0 :     VSIFPrintfL(fp, "geo points = {\n");
    1085               0 :     for (int iR=0; iR<iNum; iR++)
    1086                 :     {
    1087                 :       VSIFPrintfL(fp, " %#0.4f, %#0.4f, %#0.8f, %#0.8f",
    1088               0 :                   pGcpStructs[iR].dfGCPPixel, pGcpStructs[iR].dfGCPLine,
    1089               0 :                   pGcpStructs[iR].dfGCPY, pGcpStructs[iR].dfGCPX);
    1090               0 :       if (iR<iNum-1)
    1091               0 :         VSIFPrintfL(fp, ",\n");
    1092                 :     }
    1093                 : 
    1094               0 :     VSIFPrintfL(fp, "}\n" );
    1095                 : 
    1096               0 :     return TRUE;
    1097                 : }
    1098                 : 
    1099                 : /************************************************************************/
    1100                 : /*                          GetProjectionRef()                          */
    1101                 : /************************************************************************/
    1102                 : 
    1103              20 : const char *ENVIDataset::GetProjectionRef()
    1104                 : 
    1105                 : {
    1106              20 :     return pszProjection;
    1107                 : }
    1108                 : 
    1109                 : /************************************************************************/
    1110                 : /*                          SetProjection()                             */
    1111                 : /************************************************************************/
    1112                 : 
    1113              46 : CPLErr ENVIDataset::SetProjection( const char *pszNewProjection )
    1114                 : 
    1115                 : {
    1116              46 :     CPLFree( pszProjection );
    1117              46 :     pszProjection = CPLStrdup( pszNewProjection );
    1118                 : 
    1119              46 :     bHeaderDirty = TRUE;
    1120                 : 
    1121              46 :     return CE_None;
    1122                 : }
    1123                 : 
    1124                 : /************************************************************************/
    1125                 : /*                          GetGeoTransform()                           */
    1126                 : /************************************************************************/
    1127                 : 
    1128              38 : CPLErr ENVIDataset::GetGeoTransform( double * padfTransform )
    1129                 : 
    1130                 : {
    1131              38 :     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1132                 :     
    1133              38 :     if( bFoundMapinfo )
    1134              36 :         return CE_None;
    1135                 :     else
    1136               2 :         return CE_Failure;
    1137                 : }
    1138                 : 
    1139                 : /************************************************************************/
    1140                 : /*                          SetGeoTransform()                           */
    1141                 : /************************************************************************/
    1142                 : 
    1143              47 : CPLErr ENVIDataset::SetGeoTransform( double * padfTransform )
    1144                 : {
    1145              47 :     memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
    1146                 : 
    1147              47 :     bHeaderDirty = TRUE;
    1148              47 :     bFoundMapinfo = TRUE;
    1149                 :     
    1150              47 :     return CE_None;
    1151                 : }
    1152                 : 
    1153                 : /************************************************************************/
    1154                 : /*                           SetDescription()                           */
    1155                 : /************************************************************************/
    1156                 : 
    1157             114 : void ENVIDataset::SetDescription( const char * pszDescription )
    1158                 : {
    1159             114 :     bHeaderDirty = TRUE;
    1160             114 :     RawDataset::SetDescription(pszDescription);
    1161             114 : }
    1162                 : 
    1163                 : /************************************************************************/
    1164                 : /*                             SetMetadata()                            */
    1165                 : /************************************************************************/
    1166                 : 
    1167              22 : CPLErr ENVIDataset::SetMetadata( char ** papszMetadata,
    1168                 :                                  const char * pszDomain )
    1169                 : {  
    1170              22 :     if( pszDomain && (EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "ENVI")) )
    1171                 :     {
    1172               2 :         bHeaderDirty = TRUE;
    1173                 :     }
    1174              22 :     return RawDataset::SetMetadata(papszMetadata, pszDomain);
    1175                 : }
    1176                 : 
    1177                 : /************************************************************************/
    1178                 : /*                             SetMetadataItem()                        */
    1179                 : /************************************************************************/
    1180                 : 
    1181            1428 : CPLErr ENVIDataset::SetMetadataItem( const char * pszName,
    1182                 :                                      const char * pszValue,
    1183                 :                                      const char * pszDomain )
    1184                 : {
    1185            1428 :     if( pszDomain && (EQUAL(pszDomain, "RPC") || EQUAL(pszDomain, "ENVI")) )
    1186                 :     {
    1187            1222 :         bHeaderDirty = TRUE;
    1188                 :     }
    1189            1428 :     return RawDataset::SetMetadataItem(pszName, pszValue, pszDomain);
    1190                 : }
    1191                 : 
    1192                 : /************************************************************************/
    1193                 : /*                               SetGCPs()                              */
    1194                 : /************************************************************************/
    1195                 : 
    1196               0 : CPLErr ENVIDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
    1197                 :                              const char *pszGCPProjection )
    1198                 : {
    1199               0 :     bHeaderDirty = TRUE;
    1200                 : 
    1201               0 :     return RawDataset::SetGCPs(nGCPCount, pasGCPList, pszGCPProjection);
    1202                 : }
    1203                 : 
    1204                 : /************************************************************************/
    1205                 : /*                             SplitList()                              */
    1206                 : /*                                                                      */
    1207                 : /*      Split an ENVI value list into component fields, and strip       */
    1208                 : /*      white space.                                                    */
    1209                 : /************************************************************************/
    1210                 : 
    1211             204 : char **ENVIDataset::SplitList( const char *pszCleanInput )
    1212                 : 
    1213                 : {
    1214             204 :     char  **papszReturn = NULL;
    1215             204 :     char  *pszInput = CPLStrdup(pszCleanInput);
    1216                 : 
    1217             204 :     if( pszInput[0] != '{' )
    1218                 :     {
    1219              62 :         CPLFree(pszInput);
    1220              62 :         return NULL;
    1221                 :     }
    1222                 : 
    1223             142 :     int iChar=1;
    1224                 : 
    1225                 : 
    1226            1276 :     while( pszInput[iChar] != '}' && pszInput[iChar] != '\0' )
    1227                 :     {
    1228             992 :         int iFStart=-1, iFEnd=-1;
    1229                 : 
    1230                 :         // Find start of token.
    1231             992 :         iFStart = iChar;
    1232            3036 :         while( pszInput[iFStart] == ' ' )
    1233            1052 :             iFStart++;
    1234                 : 
    1235             992 :         iFEnd = iFStart;
    1236           19718 :         while( pszInput[iFEnd] != ',' 
    1237            6006 :                && pszInput[iFEnd] != '}'
    1238            5864 :                && pszInput[iFEnd] != '\0' )
    1239            5864 :             iFEnd++;
    1240                 : 
    1241             992 :         if( pszInput[iFEnd] == '\0' )
    1242               0 :             break;
    1243                 : 
    1244             992 :         iChar = iFEnd + 1;
    1245             992 :         iFEnd = iFEnd - 1;
    1246                 : 
    1247            1984 :         while( iFEnd > iFStart && pszInput[iFEnd] == ' ' )
    1248               0 :             iFEnd--;
    1249                 : 
    1250             992 :         pszInput[iFEnd + 1] = '\0';
    1251             992 :         papszReturn = CSLAddString( papszReturn, pszInput + iFStart );
    1252                 :     }
    1253                 : 
    1254             142 :     CPLFree( pszInput );
    1255                 : 
    1256             142 :     return papszReturn;
    1257                 : }
    1258                 : 
    1259                 : /************************************************************************/
    1260                 : /*                            SetENVIDatum()                            */
    1261                 : /************************************************************************/
    1262                 : 
    1263               0 : void ENVIDataset::SetENVIDatum( OGRSpatialReference *poSRS, 
    1264                 :                                 const char *pszENVIDatumName )
    1265                 : 
    1266                 : {
    1267                 :     // datums
    1268               0 :     if( EQUAL(pszENVIDatumName, "WGS-84") )
    1269               0 :         poSRS->SetWellKnownGeogCS( "WGS84" );
    1270               0 :     else if( EQUAL(pszENVIDatumName, "WGS-72") )
    1271               0 :         poSRS->SetWellKnownGeogCS( "WGS72" );
    1272               0 :     else if( EQUAL(pszENVIDatumName, "North America 1983") )
    1273               0 :         poSRS->SetWellKnownGeogCS( "NAD83" );
    1274               0 :     else if( EQUAL(pszENVIDatumName, "North America 1927") 
    1275                 :              || strstr(pszENVIDatumName,"NAD27") 
    1276                 :              || strstr(pszENVIDatumName,"NAD-27") )
    1277               0 :         poSRS->SetWellKnownGeogCS( "NAD27" );
    1278               0 :     else if( EQUALN(pszENVIDatumName, "European 1950",13) )
    1279               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4230" );
    1280               0 :     else if( EQUAL(pszENVIDatumName, "Ordnance Survey of Great Britain '36") )
    1281               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4277" );
    1282               0 :     else if( EQUAL(pszENVIDatumName, "SAD-69/Brazil") )
    1283               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4291" );
    1284               0 :     else if( EQUAL(pszENVIDatumName, "Geocentric Datum of Australia 1994") )
    1285               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4283" );
    1286               0 :     else if( EQUAL(pszENVIDatumName, "Australian Geodetic 1984") )
    1287               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4203" );
    1288               0 :     else if( EQUAL(pszENVIDatumName, "Nouvelle Triangulation Francaise IGN") )
    1289               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4275" );
    1290                 : 
    1291                 :     // Ellipsoids
    1292               0 :     else if( EQUAL(pszENVIDatumName, "GRS 80") )
    1293               0 :         poSRS->SetWellKnownGeogCS( "NAD83" );
    1294               0 :     else if( EQUAL(pszENVIDatumName, "Airy") )
    1295               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4001" );
    1296               0 :     else if( EQUAL(pszENVIDatumName, "Australian National") )
    1297               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4003" );
    1298               0 :     else if( EQUAL(pszENVIDatumName, "Bessel 1841") )
    1299               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4004" );
    1300               0 :     else if( EQUAL(pszENVIDatumName, "Clark 1866") )
    1301               0 :         poSRS->SetWellKnownGeogCS( "EPSG:4008" );
    1302                 :     else 
    1303                 :     {
    1304                 :         CPLError( CE_Warning, CPLE_AppDefined,
    1305               0 :                   "Unrecognised datum '%s', defaulting to WGS84.", pszENVIDatumName);
    1306               0 :         poSRS->SetWellKnownGeogCS( "WGS84" );
    1307                 :     }
    1308               0 : }
    1309                 : 
    1310                 : /************************************************************************/
    1311                 : /*                           SetENVIEllipse()                           */
    1312                 : /************************************************************************/
    1313                 : 
    1314               7 : void ENVIDataset::SetENVIEllipse( OGRSpatialReference *poSRS, 
    1315                 :                                   char **papszPI_EI )
    1316                 : 
    1317                 : {
    1318               7 :     double dfA = CPLAtofM(papszPI_EI[0]);
    1319               7 :     double dfB = CPLAtofM(papszPI_EI[1]);
    1320                 :     double dfInvF;
    1321                 : 
    1322               7 :     if( fabs(dfA-dfB) < 0.1 )
    1323               0 :         dfInvF = 0.0; // sphere
    1324                 :     else
    1325               7 :         dfInvF = dfA / (dfA - dfB);
    1326                 :     
    1327                 :     
    1328                 :     poSRS->SetGeogCS( "Ellipse Based", "Ellipse Based", "Unnamed", 
    1329               7 :                       dfA, dfInvF );
    1330               7 : }
    1331                 : 
    1332                 : /************************************************************************/
    1333                 : /*                           ProcessMapinfo()                           */
    1334                 : /*                                                                      */
    1335                 : /*      Extract projection, and geotransform from a mapinfo value in    */
    1336                 : /*      the header.                                                     */
    1337                 : /************************************************************************/
    1338                 : 
    1339              52 : int ENVIDataset::ProcessMapinfo( const char *pszMapinfo )
    1340                 : 
    1341                 : {
    1342                 :     char  **papszFields;    
    1343                 :     int         nCount;
    1344              52 :     OGRSpatialReference oSRS;
    1345                 : 
    1346              52 :     papszFields = SplitList( pszMapinfo );
    1347              52 :     nCount = CSLCount(papszFields);
    1348                 : 
    1349              52 :     if( nCount < 7 )
    1350                 :     {
    1351               0 :         CSLDestroy( papszFields );
    1352               0 :         return FALSE;
    1353                 :     }
    1354                 : 
    1355                 : /* -------------------------------------------------------------------- */
    1356                 : /*      Check if we have coordinate system string, and if so parse it.  */
    1357                 : /* -------------------------------------------------------------------- */
    1358              52 :     char **papszCSS = NULL;
    1359              52 :     if( CSLFetchNameValue( papszHeader, "coordinate_system_string" ) != NULL )
    1360                 :     {
    1361                 :         papszCSS = CSLTokenizeString2(
    1362                 :             CSLFetchNameValue( papszHeader, "coordinate_system_string" ), 
    1363              37 :             "{}", CSLT_PRESERVEQUOTES );
    1364                 :     }
    1365                 : 
    1366                 : /* -------------------------------------------------------------------- */
    1367                 : /*      Check if we have projection info, and if so parse it.           */
    1368                 : /* -------------------------------------------------------------------- */
    1369              52 :     char        **papszPI = NULL;
    1370              52 :     int         nPICount = 0;
    1371              52 :     if( CSLFetchNameValue( papszHeader, "projection_info" ) != NULL )
    1372                 :     {
    1373                 :         papszPI = SplitList( 
    1374              19 :             CSLFetchNameValue( papszHeader, "projection_info" ) );
    1375              19 :         nPICount = CSLCount(papszPI);
    1376                 :     }
    1377                 : 
    1378                 : /* -------------------------------------------------------------------- */
    1379                 : /*      Capture geotransform.                                           */
    1380                 : /* -------------------------------------------------------------------- */
    1381              52 :     adfGeoTransform[1] = atof(papszFields[5]);      // Pixel width
    1382              52 :     adfGeoTransform[5] = -atof(papszFields[6]);     // Pixel height
    1383                 :     adfGeoTransform[0] =          // Upper left X coordinate
    1384              52 :   atof(papszFields[3]) - (atof(papszFields[1]) - 1) * adfGeoTransform[1];
    1385                 :     adfGeoTransform[3] =          // Upper left Y coordinate
    1386              52 :   atof(papszFields[4]) - (atof(papszFields[2]) - 1) * adfGeoTransform[5];
    1387              52 :     adfGeoTransform[2] = 0.0;
    1388              52 :     adfGeoTransform[4] = 0.0;
    1389                 : 
    1390                 : /* -------------------------------------------------------------------- */
    1391                 : /*      Capture projection.                                             */
    1392                 : /* -------------------------------------------------------------------- */
    1393              52 :     if ( oSRS.importFromESRI( papszCSS ) != OGRERR_NONE )
    1394                 :     {
    1395              15 :         oSRS.Clear();
    1396                 : 
    1397              22 :         if( EQUALN(papszFields[0],"UTM",3) && nCount >= 9 )
    1398                 :         {
    1399               7 :             oSRS.SetUTM( atoi(papszFields[7]), 
    1400              14 :                          !EQUAL(papszFields[8],"South") );
    1401               7 :             if( nCount >= 10 && strstr(papszFields[9],"=") == NULL )
    1402               0 :                 SetENVIDatum( &oSRS, papszFields[9] );
    1403                 :             else
    1404               7 :                 oSRS.SetWellKnownGeogCS( "NAD27" );
    1405                 :         }
    1406               8 :         else if( EQUALN(papszFields[0],"State Plane (NAD 27)",19)
    1407                 :                  && nCount >= 7 )
    1408                 :         {
    1409               0 :             oSRS.SetStatePlane( ITTVISToUSGSZone(atoi(papszFields[7])), FALSE );
    1410                 :         }
    1411               8 :         else if( EQUALN(papszFields[0],"State Plane (NAD 83)",19)
    1412                 :                  && nCount >= 7 )
    1413                 :         {
    1414               0 :             oSRS.SetStatePlane( ITTVISToUSGSZone(atoi(papszFields[7])), TRUE );
    1415                 :         }
    1416               8 :         else if( EQUALN(papszFields[0],"Geographic Lat",14) 
    1417                 :                  && nCount >= 8 )
    1418                 :         {
    1419               0 :             if( nCount >= 8 && strstr(papszFields[7],"=") == NULL )
    1420               0 :                 SetENVIDatum( &oSRS, papszFields[7] );
    1421                 :             else
    1422               0 :                 oSRS.SetWellKnownGeogCS( "WGS84" );
    1423                 :         }
    1424               8 :         else if( nPICount > 8 && atoi(papszPI[0]) == 3 ) // TM
    1425                 :         {
    1426               0 :             oSRS.SetTM( CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]),
    1427               0 :                         CPLAtofM(papszPI[7]),
    1428               0 :                         CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1429                 :         }
    1430               8 :         else if( nPICount > 8 && atoi(papszPI[0]) == 4 ) // Lambert Conformal Conic
    1431                 :         {
    1432               0 :             oSRS.SetLCC( CPLAtofM(papszPI[7]), CPLAtofM(papszPI[8]),
    1433               0 :                          CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]),
    1434               0 :                          CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1435                 :         }
    1436               8 :         else if( nPICount > 10 && atoi(papszPI[0]) == 5 ) // Oblique Merc (2 point)
    1437                 :         {
    1438               0 :             oSRS.SetHOM2PNO( CPLAtofM(papszPI[3]), 
    1439               0 :                              CPLAtofM(papszPI[4]), CPLAtofM(papszPI[5]), 
    1440               0 :                              CPLAtofM(papszPI[6]), CPLAtofM(papszPI[7]), 
    1441               0 :                              CPLAtofM(papszPI[10]), 
    1442               0 :                              CPLAtofM(papszPI[8]), CPLAtofM(papszPI[9]) );
    1443                 :         }
    1444               8 :         else if( nPICount > 8 && atoi(papszPI[0]) == 6 ) // Oblique Merc 
    1445                 :         {
    1446               0 :             oSRS.SetHOM(CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]), 
    1447               0 :                         CPLAtofM(papszPI[5]), 0.0,
    1448               0 :                         CPLAtofM(papszPI[8]), 
    1449               0 :                         CPLAtofM(papszPI[6]), CPLAtofM(papszPI[7]) );
    1450                 :         }
    1451               8 :         else if( nPICount > 8 && atoi(papszPI[0]) == 7 ) // Stereographic
    1452                 :         {
    1453               0 :             oSRS.SetStereographic( CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]),
    1454               0 :                                    CPLAtofM(papszPI[7]),
    1455               0 :                                    CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1456                 :         }
    1457              15 :         else if( nPICount > 8 && atoi(papszPI[0]) == 9 ) // Albers Equal Area
    1458                 :         {
    1459              14 :             oSRS.SetACEA( CPLAtofM(papszPI[7]), CPLAtofM(papszPI[8]),
    1460              14 :                           CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]),
    1461              35 :                           CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1462                 :         }
    1463               1 :         else if( nPICount > 6 && atoi(papszPI[0]) == 10 ) // Polyconic
    1464                 :         {
    1465               0 :             oSRS.SetPolyconic(CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]), 
    1466               0 :                               CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1467                 :         }
    1468               1 :         else if( nPICount > 6 && atoi(papszPI[0]) == 11 ) // LAEA
    1469                 :         {
    1470               0 :             oSRS.SetLAEA(CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]), 
    1471               0 :                          CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1472                 :         }
    1473               1 :         else if( nPICount > 6 && atoi(papszPI[0]) == 12 ) // Azimuthal Equid.
    1474                 :         {
    1475               0 :             oSRS.SetAE(CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]), 
    1476               0 :                        CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1477                 :         }
    1478               1 :         else if( nPICount > 6 && atoi(papszPI[0]) == 31 ) // Polar Stereographic
    1479                 :         {
    1480               0 :             oSRS.SetPS(CPLAtofM(papszPI[3]), CPLAtofM(papszPI[4]), 
    1481                 :                        1.0,
    1482               0 :                        CPLAtofM(papszPI[5]), CPLAtofM(papszPI[6]) );
    1483                 :         }
    1484                 :     }
    1485                 : 
    1486              52 :     CSLDestroy( papszCSS );
    1487                 : 
    1488                 :     // Still lots more that could be added for someone with the patience.
    1489                 : 
    1490                 : /* -------------------------------------------------------------------- */
    1491                 : /*      fallback to localcs if we don't recognise things.               */
    1492                 : /* -------------------------------------------------------------------- */
    1493              52 :     if( oSRS.GetRoot() == NULL )
    1494               1 :         oSRS.SetLocalCS( papszFields[0] );
    1495                 : 
    1496                 : /* -------------------------------------------------------------------- */
    1497                 : /*      Try to set datum from projection info line if we have a         */
    1498                 : /*      projected coordinate system without a GEOGCS.                   */
    1499                 : /* -------------------------------------------------------------------- */
    1500              52 :     if( oSRS.IsProjected() && oSRS.GetAttrNode("GEOGCS") == NULL 
    1501                 :         && nPICount > 3 )
    1502                 :     {
    1503                 :         // Do we have a datum on the projection info line?
    1504               7 :         int iDatum = nPICount-1;
    1505                 : 
    1506                 :         // Ignore units= items.
    1507               7 :         if( strstr(papszPI[iDatum],"=") != NULL )
    1508               0 :             iDatum--;
    1509                 : 
    1510                 :         // Skip past the name. 
    1511               7 :         iDatum--;
    1512                 :     
    1513               7 :         CPLString osDatumName = papszPI[iDatum];
    1514               7 :         if( osDatumName.find_first_of("abcdefghijklmnopqrstuvwxyz"
    1515                 :                                       "ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
    1516                 :             != CPLString::npos )
    1517                 :         {
    1518               0 :             SetENVIDatum( &oSRS, osDatumName );
    1519                 :         }
    1520                 :         else
    1521                 :         {
    1522               7 :             SetENVIEllipse( &oSRS, papszPI + 1 );
    1523               7 :         }
    1524                 :     }
    1525                 : 
    1526                 : 
    1527                 : /* -------------------------------------------------------------------- */
    1528                 : /*      Try to process specialized units.                               */
    1529                 : /* -------------------------------------------------------------------- */
    1530              52 :     if( EQUALN( papszFields[nCount-1],"units",5))
    1531                 :     {
    1532                 :         /* Handle linear units first. */
    1533               0 :         if (EQUAL(papszFields[nCount-1],"units=Feet") )
    1534               0 :             oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_FOOT, atof(SRS_UL_FOOT_CONV) );
    1535               0 :         else if (EQUAL(papszFields[nCount-1],"units=Meters") )
    1536               0 :             oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_METER, 1. );
    1537               0 :         else if (EQUAL(papszFields[nCount-1],"units=Km") )
    1538               0 :             oSRS.SetLinearUnitsAndUpdateParameters( "Kilometer", 1000.  );
    1539               0 :         else if (EQUAL(papszFields[nCount-1],"units=Yards") )
    1540               0 :             oSRS.SetLinearUnitsAndUpdateParameters( "Yard", .9144 );
    1541               0 :         else if (EQUAL(papszFields[nCount-1],"units=Miles") )
    1542               0 :             oSRS.SetLinearUnitsAndUpdateParameters( "Mile", 1609.344 );
    1543               0 :         else if (EQUAL(papszFields[nCount-1],"units=Nautical Miles") )
    1544               0 :             oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_NAUTICAL_MILE, atof(SRS_UL_NAUTICAL_MILE_CONV) );
    1545                 :       
    1546                 :         /* Only handle angular units if we know the projection is geographic. */
    1547               0 :         if (oSRS.IsGeographic()) 
    1548                 :         {
    1549               0 :             if (EQUAL(papszFields[nCount-1],"units=Radians") )
    1550               0 :                 oSRS.SetAngularUnits( SRS_UA_RADIAN, 1. );
    1551                 :             else 
    1552                 :             {
    1553                 :                 /* Degrees, minutes and seconds will all be represented as degrees. */
    1554               0 :                 oSRS.SetAngularUnits( SRS_UA_DEGREE,  atof(SRS_UA_DEGREE_CONV));
    1555                 : 
    1556               0 :                 double conversionFactor = 1.;
    1557               0 :                 if (EQUAL(papszFields[nCount-1],"units=Minutes") )
    1558               0 :                     conversionFactor = 60.;
    1559               0 :                 else if( EQUAL(papszFields[nCount-1],"units=Seconds") )
    1560               0 :                     conversionFactor = 3600.;
    1561               0 :                 adfGeoTransform[0] /= conversionFactor;
    1562               0 :                 adfGeoTransform[1] /= conversionFactor;
    1563               0 :                 adfGeoTransform[2] /= conversionFactor;
    1564               0 :                 adfGeoTransform[3] /= conversionFactor;
    1565               0 :                 adfGeoTransform[4] /= conversionFactor;
    1566               0 :                 adfGeoTransform[5] /= conversionFactor;
    1567                 :             }
    1568                 :         }
    1569                 :     }
    1570                 : /* -------------------------------------------------------------------- */
    1571                 : /*      Turn back into WKT.                                             */
    1572                 : /* -------------------------------------------------------------------- */
    1573              52 :     if( oSRS.GetRoot() != NULL )
    1574                 :     {
    1575              52 :         oSRS.Fixup();
    1576              52 :   if ( pszProjection )
    1577                 :   {
    1578              52 :       CPLFree( pszProjection );
    1579              52 :       pszProjection = NULL;
    1580                 :   }
    1581              52 :         oSRS.exportToWkt( &pszProjection );
    1582                 :     }
    1583                 : 
    1584              52 :     CSLDestroy( papszFields );
    1585              52 :     CSLDestroy( papszPI );
    1586              52 :     return TRUE;
    1587                 : }
    1588                 : 
    1589                 : /************************************************************************/
    1590                 : /*                           ProcessRPCinfo()                           */
    1591                 : /*                                                                      */
    1592                 : /*      Extract RPC transformation coefficients if they are present     */
    1593                 : /*      and sets into the standard metadata fields for RPC.             */
    1594                 : /************************************************************************/
    1595                 : 
    1596               3 : void ENVIDataset::ProcessRPCinfo( const char *pszRPCinfo, 
    1597                 :                                  int numCols, int numRows)
    1598                 : {
    1599                 :     char  **papszFields;
    1600                 :     char    sVal[1280];
    1601                 :     int         nCount;
    1602                 : 
    1603               3 :     papszFields = SplitList( pszRPCinfo );
    1604               3 :     nCount = CSLCount(papszFields);
    1605                 : 
    1606               3 :     if( nCount < 90 )
    1607                 :     {
    1608               0 :         CSLDestroy( papszFields );
    1609               0 :         return;
    1610                 :     }
    1611                 :   
    1612               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[0]));
    1613               3 :     SetMetadataItem("LINE_OFF",sVal,"RPC");
    1614               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[5]));
    1615               3 :     SetMetadataItem("LINE_SCALE",sVal,"RPC");
    1616               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[1]));
    1617               3 :     SetMetadataItem("SAMP_OFF",sVal,"RPC");
    1618               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[6]));
    1619               3 :     SetMetadataItem("SAMP_SCALE",sVal,"RPC");
    1620               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[2]));
    1621               3 :     SetMetadataItem("LAT_OFF",sVal,"RPC");
    1622               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[7]));
    1623               3 :     SetMetadataItem("LAT_SCALE",sVal,"RPC");
    1624               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[3]));
    1625               3 :     SetMetadataItem("LONG_OFF",sVal,"RPC");
    1626               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[8]));
    1627               3 :     SetMetadataItem("LONG_SCALE",sVal,"RPC");
    1628               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[4]));
    1629               3 :     SetMetadataItem("HEIGHT_OFF",sVal,"RPC");
    1630               3 :     snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[9]));
    1631               3 :     SetMetadataItem("HEIGHT_SCALE",sVal,"RPC");
    1632                 : 
    1633               3 :     sVal[0] = '\0'; 
    1634                 :     int i;
    1635              63 :     for(i = 0; i < 20; i++ )
    1636                 :        snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ", 
    1637              60 :            atof(papszFields[10+i]));
    1638               3 :     SetMetadataItem("LINE_NUM_COEFF",sVal,"RPC");
    1639                 : 
    1640               3 :     sVal[0] = '\0'; 
    1641              63 :     for(i = 0; i < 20; i++ )
    1642                 :        snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
    1643              60 :            atof(papszFields[30+i]));
    1644               3 :     SetMetadataItem("LINE_DEN_COEFF",sVal,"RPC");
    1645                 :       
    1646               3 :     sVal[0] = '\0'; 
    1647              63 :     for(i = 0; i < 20; i++ )
    1648                 :        snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
    1649              60 :            atof(papszFields[50+i]));
    1650               3 :     SetMetadataItem("SAMP_NUM_COEFF",sVal,"RPC");
    1651                 :       
    1652               3 :     sVal[0] = '\0'; 
    1653              63 :     for(i = 0; i < 20; i++ )
    1654                 :        snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
    1655              60 :            atof(papszFields[70+i]));
    1656               3 :     SetMetadataItem("SAMP_DEN_COEFF",sVal,"RPC");
    1657                 :   
    1658                 :     snprintf(sVal, sizeof(sVal), "%.16g", 
    1659               3 :         atof(papszFields[3]) - atof(papszFields[8]));
    1660               3 :     SetMetadataItem("MIN_LONG",sVal,"RPC");
    1661                 : 
    1662                 :     snprintf(sVal, sizeof(sVal), "%.16g", 
    1663               3 :         atof(papszFields[3]) + atof(papszFields[8]) );
    1664               3 :     SetMetadataItem("MAX_LONG",sVal,"RPC");
    1665                 : 
    1666                 :     snprintf(sVal, sizeof(sVal), "%.16g",
    1667               3 :         atof(papszFields[2]) - atof(papszFields[7]));
    1668               3 :     SetMetadataItem("MIN_LAT",sVal,"RPC");
    1669                 : 
    1670                 :     snprintf(sVal, sizeof(sVal), "%.16g",
    1671               3 :         atof(papszFields[2]) + atof(papszFields[7]));
    1672               3 :     SetMetadataItem("MAX_LAT",sVal,"RPC");
    1673                 : 
    1674               3 :     if (nCount == 93)
    1675                 :     {
    1676               3 :         SetMetadataItem("TILE_ROW_OFFSET",papszFields[90],"RPC");
    1677               3 :         SetMetadataItem("TILE_COL_OFFSET",papszFields[91],"RPC");
    1678               3 :         SetMetadataItem("ENVI_RPC_EMULATION",papszFields[92],"RPC");
    1679                 :     }
    1680                 : 
    1681                 :     /*   Handle the chipping case where the image is a subset. */
    1682                 :     double rowOffset, colOffset;
    1683               3 :     rowOffset = (nCount == 93) ? atof(papszFields[90]) : 0;
    1684               3 :     colOffset = (nCount == 93) ? atof(papszFields[91]) : 0;
    1685               3 :     if (rowOffset || colOffset)
    1686                 :     {
    1687               0 :         SetMetadataItem("ICHIP_SCALE_FACTOR", "1");
    1688               0 :         SetMetadataItem("ICHIP_ANAMORPH_CORR", "0");
    1689               0 :         SetMetadataItem("ICHIP_SCANBLK_NUM", "0");
    1690                 : 
    1691               0 :         SetMetadataItem("ICHIP_OP_ROW_11", "0.5");
    1692               0 :         SetMetadataItem("ICHIP_OP_COL_11", "0.5");
    1693               0 :         SetMetadataItem("ICHIP_OP_ROW_12", "0.5");
    1694               0 :         SetMetadataItem("ICHIP_OP_COL_21", "0.5");
    1695               0 :         snprintf(sVal, sizeof(sVal), "%.16g", numCols - 0.5);
    1696               0 :         SetMetadataItem("ICHIP_OP_COL_12", sVal);
    1697               0 :         SetMetadataItem("ICHIP_OP_COL_22", sVal);
    1698               0 :         snprintf(sVal, sizeof(sVal), "%.16g", numRows - 0.5);
    1699               0 :         SetMetadataItem("ICHIP_OP_ROW_21", sVal);
    1700               0 :         SetMetadataItem("ICHIP_OP_ROW_22", sVal);
    1701                 : 
    1702               0 :         snprintf(sVal, sizeof(sVal), "%.16g", rowOffset + 0.5);
    1703               0 :         SetMetadataItem("ICHIP_FI_ROW_11", sVal);
    1704               0 :         SetMetadataItem("ICHIP_FI_ROW_12", sVal);
    1705               0 :         snprintf(sVal, sizeof(sVal), "%.16g", colOffset + 0.5);
    1706               0 :         SetMetadataItem("ICHIP_FI_COL_11", sVal);
    1707               0 :         SetMetadataItem("ICHIP_FI_COL_21", sVal);
    1708               0 :         snprintf(sVal, sizeof(sVal), "%.16g", colOffset + numCols - 0.5);
    1709               0 :         SetMetadataItem("ICHIP_FI_COL_12", sVal);
    1710               0 :         SetMetadataItem("ICHIP_FI_COL_22", sVal);
    1711               0 :         snprintf(sVal, sizeof(sVal), "%.16g", rowOffset + numRows - 0.5);
    1712               0 :         SetMetadataItem("ICHIP_FI_ROW_21", sVal);
    1713               0 :         SetMetadataItem("ICHIP_FI_ROW_22", sVal);
    1714                 :     }
    1715               3 :     CSLDestroy(papszFields);
    1716                 : }
    1717                 : 
    1718             114 : void ENVIDataset::ProcessStatsFile()
    1719                 : {
    1720                 :     VSILFILE  *fpStaFile;
    1721                 : 
    1722             114 :     osStaFilename = CPLResetExtension( pszHDRFilename, "sta" );
    1723             114 :     fpStaFile = VSIFOpenL( osStaFilename, "rb" );
    1724                 : 
    1725             114 :     if (!fpStaFile)
    1726                 :     {
    1727             113 :         osStaFilename = "";
    1728             113 :         return;
    1729                 :     }
    1730                 : 
    1731                 :     int lTestHeader[10],lOffset;
    1732                 : 
    1733               1 :     if( VSIFReadL( lTestHeader, sizeof(int), 10, fpStaFile ) != 10 )
    1734                 :     {
    1735               0 :         VSIFCloseL( fpStaFile );
    1736               0 :         osStaFilename = "";
    1737               0 :         return;
    1738                 :     }
    1739                 : 
    1740                 :     int isFloat;
    1741               1 :     isFloat = (byteSwapInt(lTestHeader[0]) == 1111838282);
    1742                 : 
    1743                 :     int nb,i;
    1744                 :     float * fStats;
    1745                 :     double * dStats, dMin, dMax, dMean, dStd;
    1746                 :         
    1747               1 :     nb=byteSwapInt(lTestHeader[3]);
    1748                 :     
    1749               1 :     if (nb < 0 || nb > nBands)
    1750                 :     {
    1751                 :         CPLDebug("ENVI", ".sta file has statistics for %d bands, "
    1752               0 :                          "whereas the dataset has only %d bands", nb, nBands);
    1753               0 :         nb = nBands;
    1754                 :     }
    1755                 :     
    1756               1 :     VSIFSeekL(fpStaFile,40+(nb+1)*4,SEEK_SET);
    1757                 : 
    1758               1 :     if (VSIFReadL(&lOffset,sizeof(int),1,fpStaFile) == 1)
    1759                 :     {
    1760               1 :         VSIFSeekL(fpStaFile,40+(nb+1)*8+byteSwapInt(lOffset)+nb,SEEK_SET);
    1761                 :         // This should be the beginning of the statistics
    1762               1 :         if (isFloat)
    1763                 :         {
    1764               0 :             fStats = (float*)CPLCalloc(nb*4,4);
    1765               0 :             if ((int)VSIFReadL(fStats,4,nb*4,fpStaFile) == nb*4)
    1766                 :             {
    1767               0 :                 for (i=0;i<nb;i++)
    1768                 :                 {
    1769                 :                     GetRasterBand(i+1)->SetStatistics(
    1770                 :                         byteSwapFloat(fStats[i]),
    1771                 :                         byteSwapFloat(fStats[nb+i]),
    1772                 :                         byteSwapFloat(fStats[2*nb+i]), 
    1773               0 :                         byteSwapFloat(fStats[3*nb+i]));
    1774                 :                 }
    1775                 :             }
    1776               0 :             CPLFree(fStats);
    1777                 :         }
    1778                 :         else
    1779                 :         {
    1780               1 :             dStats = (double*)CPLCalloc(nb*4,8);
    1781               1 :             if ((int)VSIFReadL(dStats,8,nb*4,fpStaFile) == nb*4)
    1782                 :             {
    1783               7 :                 for (i=0;i<nb;i++)
    1784                 :                 {
    1785               6 :                     dMin = byteSwapDouble(dStats[i]);
    1786               6 :                     dMax = byteSwapDouble(dStats[nb+i]);
    1787               6 :                     dMean = byteSwapDouble(dStats[2*nb+i]);
    1788               6 :                     dStd = byteSwapDouble(dStats[3*nb+i]);
    1789               6 :                     if (dMin != dMax && dStd != 0) 
    1790               6 :                         GetRasterBand(i+1)->SetStatistics(dMin,dMax,dMean,dStd);
    1791                 :                 }
    1792                 :             }
    1793               1 :             CPLFree(dStats);
    1794                 :         }
    1795                 :     }
    1796               1 :     VSIFCloseL( fpStaFile );
    1797                 : }
    1798                 : 
    1799               3 : int ENVIDataset::byteSwapInt(int swapMe)
    1800                 : {
    1801               3 :     CPL_MSBPTR32(&swapMe);
    1802               3 :     return swapMe;
    1803                 : }
    1804                 : 
    1805               0 : float ENVIDataset::byteSwapFloat(float swapMe)
    1806                 : {
    1807               0 :     CPL_MSBPTR32(&swapMe);
    1808               0 :     return swapMe;
    1809                 : }
    1810                 : 
    1811              24 : double ENVIDataset::byteSwapDouble(double swapMe)
    1812                 : {
    1813              24 :     CPL_MSBPTR64(&swapMe);
    1814              24 :     return swapMe;
    1815                 : }
    1816                 : 
    1817                 : 
    1818                 : /************************************************************************/
    1819                 : /*                             ReadHeader()                             */
    1820                 : /************************************************************************/
    1821                 : 
    1822             116 : int ENVIDataset::ReadHeader( VSILFILE * fpHdr )
    1823                 : 
    1824                 : {
    1825                 : 
    1826             116 :     CPLReadLineL( fpHdr );
    1827                 : 
    1828                 : /* -------------------------------------------------------------------- */
    1829                 : /*      Now start forming sets of name/value pairs.                     */
    1830                 : /* -------------------------------------------------------------------- */
    1831            1175 :     while( TRUE )
    1832                 :     {
    1833                 :         const char *pszNewLine;
    1834                 :         char       *pszWorkingLine;
    1835                 : 
    1836            1291 :         pszNewLine = CPLReadLineL( fpHdr );
    1837            1291 :         if( pszNewLine == NULL )
    1838                 :             break;
    1839                 : 
    1840            1175 :         if( strstr(pszNewLine,"=") == NULL )
    1841               0 :             continue;
    1842                 : 
    1843            1175 :         pszWorkingLine = CPLStrdup(pszNewLine);
    1844                 : 
    1845                 :         // Collect additional lines if we have open sqiggly bracket.
    1846            1175 :         if( strstr(pszWorkingLine,"{") != NULL 
    1847                 :             && strstr(pszWorkingLine,"}") == NULL )
    1848                 :         {
    1849             225 :             do { 
    1850             225 :                 pszNewLine = CPLReadLineL( fpHdr );
    1851             225 :                 if( pszNewLine )
    1852                 :                 {
    1853                 :                     pszWorkingLine = (char *) 
    1854                 :                         CPLRealloc(pszWorkingLine, 
    1855             225 :                                  strlen(pszWorkingLine)+strlen(pszNewLine)+1);
    1856             225 :                     strcat( pszWorkingLine, pszNewLine );
    1857                 :                 }
    1858                 :             } while( pszNewLine != NULL && strstr(pszNewLine,"}") == NULL );
    1859                 :         }
    1860                 : 
    1861                 :         // Try to break input into name and value portions.  Trim whitespace.
    1862                 :         const char *pszValue;
    1863                 :         int         iEqual;
    1864                 : 
    1865           28665 :         for( iEqual = 0; 
    1866           27490 :              pszWorkingLine[iEqual] != '\0' && pszWorkingLine[iEqual] != '=';
    1867                 :              iEqual++ ) {}
    1868                 : 
    1869            1175 :         if( pszWorkingLine[iEqual] == '=' )
    1870                 :         {
    1871                 :             int   i;
    1872                 : 
    1873            1175 :             pszValue = pszWorkingLine + iEqual + 1;
    1874            3525 :             while( *pszValue == ' ' || *pszValue == '\t' )
    1875            1175 :                 pszValue++;
    1876                 :             
    1877            1175 :             pszWorkingLine[iEqual--] = '\0';
    1878            7978 :             while( iEqual > 0 
    1879            2814 :                    && (pszWorkingLine[iEqual] == ' '
    1880            1175 :                        || pszWorkingLine[iEqual] == '\t') )
    1881            1639 :                 pszWorkingLine[iEqual--] = '\0';
    1882                 : 
    1883                 :             // Convert spaces in the name to underscores.
    1884           12106 :             for( i = 0; pszWorkingLine[i] != '\0'; i++ )
    1885                 :             {
    1886           10931 :                 if( pszWorkingLine[i] == ' ' )
    1887             690 :                     pszWorkingLine[i] = '_';
    1888                 :             }
    1889                 : 
    1890                 :             papszHeader = CSLSetNameValue( papszHeader, 
    1891            1175 :                                            pszWorkingLine, pszValue );
    1892                 :         }
    1893                 : 
    1894            1175 :         CPLFree( pszWorkingLine );
    1895                 :     }
    1896                 : 
    1897             116 :     return TRUE;
    1898                 : }
    1899                 : 
    1900                 : /************************************************************************/
    1901                 : /*                                Open()                                */
    1902                 : /************************************************************************/
    1903                 : 
    1904           12384 : GDALDataset *ENVIDataset::Open( GDALOpenInfo * poOpenInfo )
    1905                 : 
    1906                 : {
    1907                 :     int   i;
    1908                 :     
    1909                 : /* -------------------------------------------------------------------- */
    1910                 : /*  We assume the user is pointing to the binary (ie. .bil) file. */
    1911                 : /* -------------------------------------------------------------------- */
    1912           12384 :     if( poOpenInfo->nHeaderBytes < 2 )
    1913           11361 :         return NULL;
    1914                 : 
    1915                 : /* -------------------------------------------------------------------- */
    1916                 : /*      Do we have a .hdr file?  Try upper and lower case, and          */
    1917                 : /*      replacing the extension as well as appending the extension      */
    1918                 : /*      to whatever we currently have.                                  */
    1919                 : /* -------------------------------------------------------------------- */
    1920                 :     const char  *pszMode;
    1921            1023 :     CPLString   osHdrFilename;
    1922            1023 :     VSILFILE  *fpHeader = NULL;
    1923                 : 
    1924            1023 :     if( poOpenInfo->eAccess == GA_Update )
    1925             238 :   pszMode = "r+";
    1926                 :     else
    1927             785 :   pszMode = "r";
    1928                 :     
    1929            1023 :     if (poOpenInfo->papszSiblingFiles == NULL)
    1930                 :     {
    1931               4 :         osHdrFilename = CPLResetExtension( poOpenInfo->pszFilename, "hdr" );
    1932               4 :         fpHeader = VSIFOpenL( osHdrFilename, pszMode );
    1933                 :     
    1934               4 :         if( fpHeader == NULL && VSIIsCaseSensitiveFS(osHdrFilename) )
    1935                 :         {
    1936               4 :             osHdrFilename = CPLResetExtension( poOpenInfo->pszFilename, "HDR" );
    1937               4 :             fpHeader = VSIFOpenL( osHdrFilename, pszMode );
    1938                 :         }
    1939                 : 
    1940               4 :         if( fpHeader == NULL )
    1941                 :         {
    1942                 :             osHdrFilename = CPLFormFilename( NULL, poOpenInfo->pszFilename, 
    1943               4 :                                             "hdr" );
    1944               4 :             fpHeader = VSIFOpenL( osHdrFilename, pszMode );
    1945                 :         }
    1946                 : 
    1947               4 :         if( fpHeader == NULL && VSIIsCaseSensitiveFS(osHdrFilename) )
    1948                 :         {
    1949                 :             osHdrFilename = CPLFormFilename( NULL, poOpenInfo->pszFilename, 
    1950               4 :                                             "HDR" );
    1951               4 :             fpHeader = VSIFOpenL( osHdrFilename, pszMode );
    1952                 :         }
    1953                 : 
    1954                 :     }
    1955                 :     else
    1956                 :     {
    1957                 :         /* -------------------------------------------------------------------- */
    1958                 :         /*      Now we need to tear apart the filename to form a .HDR           */
    1959                 :         /*      filename.                                                       */
    1960                 :         /* -------------------------------------------------------------------- */
    1961            1019 :         CPLString osPath = CPLGetPath( poOpenInfo->pszFilename );
    1962            1019 :         CPLString osName = CPLGetFilename( poOpenInfo->pszFilename );
    1963                 : 
    1964                 :         int iFile = CSLFindString(poOpenInfo->papszSiblingFiles, 
    1965            1019 :                                   CPLResetExtension( osName, "hdr" ) );
    1966            1019 :         if( iFile >= 0 )
    1967                 :         {
    1968             223 :             osHdrFilename = CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile], 
    1969             446 :                                              NULL );
    1970             223 :             fpHeader = VSIFOpenL( osHdrFilename, pszMode );
    1971                 :         }
    1972                 :         else
    1973                 :         {
    1974                 :             iFile = CSLFindString(poOpenInfo->papszSiblingFiles,
    1975             796 :                                   CPLFormFilename( NULL, osName, "hdr" ));
    1976             796 :             if( iFile >= 0 )
    1977                 :             {
    1978               0 :                 osHdrFilename = CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile], 
    1979               0 :                                                  NULL );
    1980               0 :                 fpHeader = VSIFOpenL( osHdrFilename, pszMode );
    1981                 :             }
    1982            1019 :         }
    1983                 :     }
    1984                 : 
    1985            1023 :     if( fpHeader == NULL )
    1986             800 :         return NULL;
    1987                 :     
    1988                 : /* -------------------------------------------------------------------- */
    1989                 : /*      Check that the first line says "ENVI".                          */
    1990                 : /* -------------------------------------------------------------------- */
    1991                 :     char  szTestHdr[4];
    1992                 : 
    1993             223 :     if( VSIFReadL( szTestHdr, 4, 1, fpHeader ) != 1 )
    1994                 :     {
    1995               0 :         VSIFCloseL( fpHeader );
    1996               0 :         return NULL;
    1997                 :     }
    1998             223 :     if( strncmp(szTestHdr,"ENVI",4) != 0 )
    1999                 :     {
    2000             107 :         VSIFCloseL( fpHeader );
    2001             107 :         return NULL;
    2002                 :     }
    2003                 : 
    2004                 : /* -------------------------------------------------------------------- */
    2005                 : /*      Create a corresponding GDALDataset.                             */
    2006                 : /* -------------------------------------------------------------------- */
    2007                 :     ENVIDataset   *poDS;
    2008                 : 
    2009             116 :     poDS = new ENVIDataset();
    2010             232 :     poDS->pszHDRFilename = CPLStrdup(osHdrFilename);
    2011             116 :     poDS->fp = fpHeader;
    2012                 : 
    2013                 : /* -------------------------------------------------------------------- */
    2014                 : /*      Read the header.                                                */
    2015                 : /* -------------------------------------------------------------------- */
    2016             116 :     if( !poDS->ReadHeader( fpHeader ) )
    2017                 :     {
    2018               0 :         delete poDS;
    2019               0 :         return NULL;
    2020                 :     }
    2021                 : 
    2022                 : /* -------------------------------------------------------------------- */
    2023                 : /*      Has the user selected the .hdr file to open?                    */
    2024                 : /* -------------------------------------------------------------------- */
    2025             116 :     if( EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "hdr") )
    2026                 :     {
    2027               0 :         delete poDS;
    2028                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2029                 :                   "The selected file is an ENVI header file, but to\n"
    2030                 :                   "open ENVI datasets, the data file should be selected\n"
    2031                 :                   "instead of the .hdr file.  Please try again selecting\n"
    2032                 :                   "the data file corresponding to the header file:\n"
    2033                 :                   "  %s\n", 
    2034               0 :                   poOpenInfo->pszFilename );
    2035               0 :         return NULL;
    2036                 :     }
    2037                 : 
    2038                 : /* -------------------------------------------------------------------- */
    2039                 : /*      Has the user selected the .sta (stats) file to open?            */
    2040                 : /* -------------------------------------------------------------------- */
    2041             116 :     if( EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "sta") )
    2042                 :     {
    2043               0 :         delete poDS;
    2044                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2045                 :                   "The selected file is an ENVI statistics file.\n"
    2046                 :                   "To open ENVI datasets, the data file should be selected\n"
    2047                 :                   "instead of the .sta file.  Please try again selecting\n"
    2048                 :                   "the data file corresponding to the statistics file:\n"
    2049                 :                   "  %s\n", 
    2050               0 :                   poOpenInfo->pszFilename );
    2051               0 :         return NULL;
    2052                 :     }
    2053                 : 
    2054                 : /* -------------------------------------------------------------------- */
    2055                 : /*      Extract required values from the .hdr.                          */
    2056                 : /* -------------------------------------------------------------------- */
    2057             116 :     int nLines = 0, nSamples = 0, nBands = 0, nHeaderSize = 0;
    2058             116 :     const char   *pszInterleave = NULL;
    2059                 : 
    2060             116 :     if( CSLFetchNameValue(poDS->papszHeader,"lines") )
    2061             116 :         nLines = atoi(CSLFetchNameValue(poDS->papszHeader,"lines"));
    2062                 : 
    2063             116 :     if( CSLFetchNameValue(poDS->papszHeader,"samples") )
    2064             116 :         nSamples = atoi(CSLFetchNameValue(poDS->papszHeader,"samples"));
    2065                 : 
    2066             116 :     if( CSLFetchNameValue(poDS->papszHeader,"bands") )
    2067             116 :         nBands = atoi(CSLFetchNameValue(poDS->papszHeader,"bands"));
    2068                 : 
    2069             116 :     pszInterleave = CSLFetchNameValue(poDS->papszHeader,"interleave");
    2070                 : 
    2071                 :     /* In case, there is no interleave keyword, we try to derive it from the */
    2072                 :     /* file extension. */
    2073             116 :     if( pszInterleave == NULL )
    2074                 :     {
    2075               0 :         const char* pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
    2076               0 :         pszInterleave = pszExtension;
    2077                 :     }
    2078                 : 
    2079             116 :     if ( !EQUALN(pszInterleave, "BSQ",3) &&
    2080                 :          !EQUALN(pszInterleave, "BIP",3) &&
    2081                 :          !EQUALN(pszInterleave, "BIL",3) )
    2082                 :     {
    2083               0 :         CPLDebug("ENVI", "Unset or unknown value for 'interleave' keyword --> assuming BSQ interleaving");
    2084               0 :         pszInterleave = "bsq";
    2085                 :     }
    2086                 : 
    2087             116 :     if (!GDALCheckDatasetDimensions(nSamples, nLines) || !GDALCheckBandCount(nBands, FALSE))
    2088                 :     {
    2089               2 :         delete poDS;
    2090                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2091                 :                   "The file appears to have an associated ENVI header, but\n"
    2092                 :                   "one or more of the samples, lines and bands\n"
    2093               2 :                   "keywords appears to be missing or invalid." );
    2094               2 :         return NULL;
    2095                 :     }
    2096                 : 
    2097             114 :     if( CSLFetchNameValue(poDS->papszHeader,"header_offset") )
    2098             114 :         nHeaderSize = atoi(CSLFetchNameValue(poDS->papszHeader,"header_offset"));
    2099                 : 
    2100                 : /* -------------------------------------------------------------------- */
    2101                 : /*      Translate the datatype.                                         */
    2102                 : /* -------------------------------------------------------------------- */
    2103             114 :     GDALDataType  eType = GDT_Byte;
    2104                 : 
    2105             114 :     if( CSLFetchNameValue(poDS->papszHeader,"data_type" ) != NULL )
    2106                 :     {
    2107             114 :         switch( atoi(CSLFetchNameValue(poDS->papszHeader,"data_type" )) )
    2108                 :         {
    2109                 :           case 1:
    2110              68 :             eType = GDT_Byte;
    2111              68 :             break;
    2112                 : 
    2113                 :           case 2:
    2114               6 :             eType = GDT_Int16;
    2115               6 :             break;
    2116                 : 
    2117                 :           case 3:
    2118               6 :             eType = GDT_Int32;
    2119               6 :             break;
    2120                 : 
    2121                 :           case 4:
    2122               6 :             eType = GDT_Float32;
    2123               6 :             break;
    2124                 : 
    2125                 :           case 5:
    2126               6 :             eType = GDT_Float64;
    2127               6 :             break;
    2128                 : 
    2129                 :           case 6:
    2130               5 :             eType = GDT_CFloat32;
    2131               5 :             break;
    2132                 : 
    2133                 :           case 9:
    2134               5 :             eType = GDT_CFloat64;
    2135               5 :             break;
    2136                 : 
    2137                 :           case 12:
    2138               6 :             eType = GDT_UInt16;
    2139               6 :             break;
    2140                 : 
    2141                 :           case 13:
    2142               6 :             eType = GDT_UInt32;
    2143               6 :             break;
    2144                 : 
    2145                 :             /* 14=Int64, 15=UInt64 */
    2146                 : 
    2147                 :           default:
    2148               0 :             delete poDS;
    2149                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    2150                 :                       "The file does not have a value for the data_type\n"
    2151               0 :                       "that is recognised by the GDAL ENVI driver.");
    2152               0 :             return NULL;
    2153                 :         }
    2154                 :     }
    2155                 : 
    2156                 : /* -------------------------------------------------------------------- */
    2157                 : /*      Translate the byte order.         */
    2158                 : /* -------------------------------------------------------------------- */
    2159             114 :     int   bNativeOrder = TRUE;
    2160                 : 
    2161             114 :     if( CSLFetchNameValue(poDS->papszHeader,"byte_order" ) != NULL )
    2162                 :     {
    2163                 : #ifdef CPL_LSB                               
    2164                 :         bNativeOrder = atoi(CSLFetchNameValue(poDS->papszHeader,
    2165             114 :                                               "byte_order" )) == 0;
    2166                 : #else
    2167                 :         bNativeOrder = atoi(CSLFetchNameValue(poDS->papszHeader,
    2168                 :                                               "byte_order" )) != 0;
    2169                 : #endif
    2170                 :     }
    2171                 : 
    2172                 : /* -------------------------------------------------------------------- */
    2173                 : /*      Warn about unsupported file types virtual mosaic and meta file.*/
    2174                 : /* -------------------------------------------------------------------- */
    2175             114 :     if( CSLFetchNameValue(poDS->papszHeader,"file_type" ) != NULL )
    2176                 :     {
    2177                 :         // when the file type is one of these we return an invalid file type err
    2178                 :             //'envi meta file'
    2179                 :             //'envi virtual mosaic'
    2180                 :             //'envi spectral library'
    2181                 :             //'envi fft result'
    2182                 : 
    2183                 :         // when the file type is one of these we open it 
    2184                 :             //'envi standard'
    2185                 :             //'envi classification' 
    2186                 : 
    2187                 :         // when the file type is anything else we attempt to open it as a raster.
    2188                 : 
    2189                 :         const char * pszEnviFileType;
    2190             114 :         pszEnviFileType = CSLFetchNameValue(poDS->papszHeader,"file_type");
    2191                 : 
    2192                 :         // envi gdal does not support any of these
    2193                 :         // all others we will attempt to open
    2194             114 :         if(EQUAL(pszEnviFileType, "envi meta file") ||
    2195                 :            EQUAL(pszEnviFileType, "envi virtual mosaic") ||
    2196                 :            EQUAL(pszEnviFileType, "envi spectral library"))
    2197                 :         {
    2198                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    2199                 :                       "File %s contains an invalid file type in the ENVI .hdr\n"
    2200                 :                       "GDAL does not support '%s' type files.",
    2201               0 :                       poOpenInfo->pszFilename, pszEnviFileType );
    2202               0 :             delete poDS;
    2203               0 :             return NULL;
    2204                 :         }
    2205                 :     }
    2206                 : 
    2207                 : /* -------------------------------------------------------------------- */
    2208                 : /*      Detect (gzipped) compressed datasets.                           */
    2209                 : /* -------------------------------------------------------------------- */
    2210             114 :     int bIsCompressed = FALSE;
    2211             114 :     if( CSLFetchNameValue(poDS->papszHeader,"file_compression" ) != NULL )
    2212                 :     {
    2213               1 :         if( atoi(CSLFetchNameValue(poDS->papszHeader,"file_compression" )) 
    2214                 :             != 0 )
    2215                 :         {
    2216               1 :             bIsCompressed = TRUE;
    2217                 :         }
    2218                 :     }
    2219                 : 
    2220                 : /* -------------------------------------------------------------------- */
    2221                 : /*      Capture some information from the file that is of interest.     */
    2222                 : /* -------------------------------------------------------------------- */
    2223             114 :     poDS->nRasterXSize = nSamples;
    2224             114 :     poDS->nRasterYSize = nLines;
    2225             114 :     poDS->eAccess = poOpenInfo->eAccess;
    2226                 : 
    2227                 : /* -------------------------------------------------------------------- */
    2228                 : /*      Reopen file in update mode if necessary.                        */
    2229                 : /* -------------------------------------------------------------------- */
    2230             114 :     CPLString osImageFilename(poOpenInfo->pszFilename);
    2231             114 :     if (bIsCompressed)
    2232               1 :         osImageFilename = "/vsigzip/" + osImageFilename;
    2233             114 :     if( poOpenInfo->eAccess == GA_Update )
    2234                 :     {
    2235              51 :         if (bIsCompressed)
    2236                 :         {
    2237               0 :             delete poDS;
    2238                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    2239               0 :                   "Cannot open compressed file in update mode.\n");
    2240               0 :             return NULL;
    2241                 :         }
    2242              51 :         poDS->fpImage = VSIFOpenL( osImageFilename, "rb+" );
    2243                 :     }
    2244                 :     else
    2245              63 :         poDS->fpImage = VSIFOpenL( osImageFilename, "rb" );
    2246                 : 
    2247             114 :     if( poDS->fpImage == NULL )
    2248                 :     {
    2249               0 :         delete poDS;
    2250                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    2251                 :                   "Failed to re-open %s within ENVI driver.\n", 
    2252               0 :                   poOpenInfo->pszFilename );
    2253               0 :         return NULL;
    2254                 :     }
    2255                 : 
    2256                 : /* -------------------------------------------------------------------- */
    2257                 : /*      Compute the line offset.                                        */
    2258                 : /* -------------------------------------------------------------------- */
    2259             114 :     int nDataSize = GDALGetDataTypeSize(eType)/8;
    2260                 :     int nPixelOffset, nLineOffset;
    2261                 :     vsi_l_offset nBandOffset;
    2262             114 :     int bIntOverflow = FALSE;
    2263                 :     
    2264             114 :     if( EQUALN(pszInterleave, "bil", 3) )
    2265                 :     {
    2266               0 :         poDS->interleave = BIL;
    2267               0 :         poDS->SetMetadataItem( "INTERLEAVE", "LINE", "IMAGE_STRUCTURE" );
    2268               0 :         if (nSamples > INT_MAX / (nDataSize * nBands)) bIntOverflow = TRUE;
    2269               0 :         nLineOffset = nDataSize * nSamples * nBands;
    2270               0 :         nPixelOffset = nDataSize;
    2271               0 :         nBandOffset = (vsi_l_offset)nDataSize * nSamples;
    2272                 :     }
    2273             114 :     else if( EQUALN(pszInterleave, "bip", 3) )
    2274                 :     {
    2275               0 :         poDS->interleave = BIP;
    2276               0 :         poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    2277               0 :         if (nSamples > INT_MAX / (nDataSize * nBands)) bIntOverflow = TRUE;
    2278               0 :         nLineOffset = nDataSize * nSamples * nBands;
    2279               0 :         nPixelOffset = nDataSize * nBands;
    2280               0 :         nBandOffset = nDataSize;
    2281                 :     }
    2282                 :     else /* bsq */
    2283                 :     {
    2284             114 :         poDS->interleave = BSQ;
    2285             114 :         poDS->SetMetadataItem( "INTERLEAVE", "BAND", "IMAGE_STRUCTURE" );
    2286             114 :         if (nSamples > INT_MAX / nDataSize) bIntOverflow = TRUE;
    2287             114 :         nLineOffset = nDataSize * nSamples;
    2288             114 :         nPixelOffset = nDataSize;
    2289             114 :         nBandOffset = (vsi_l_offset)nLineOffset * nLines;
    2290                 :     }
    2291                 : 
    2292             114 :     if (bIntOverflow)
    2293                 :     {
    2294               0 :         delete poDS;
    2295                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2296               0 :                   "Int overflow occured.");
    2297               0 :         return NULL;
    2298                 :     }
    2299                 :     
    2300                 : /* -------------------------------------------------------------------- */
    2301                 : /*      Create band information objects.                                */
    2302                 : /* -------------------------------------------------------------------- */
    2303             114 :     poDS->nBands = nBands;
    2304             303 :     for( i = 0; i < poDS->nBands; i++ )
    2305                 :     {
    2306                 :         poDS->SetBand( i + 1,
    2307                 :                        new ENVIRasterBand(poDS, i + 1, poDS->fpImage,
    2308                 :                                          nHeaderSize + nBandOffset * i,
    2309                 :                                          nPixelOffset, nLineOffset, eType,
    2310             189 :                                          bNativeOrder, TRUE) );
    2311                 :     }
    2312                 : 
    2313                 : /* -------------------------------------------------------------------- */
    2314                 : /*      Apply band names if we have them.                               */
    2315                 : /*      Use wavelength for more descriptive information if possible     */
    2316                 : /* -------------------------------------------------------------------- */
    2317             114 :     if( CSLFetchNameValue( poDS->papszHeader, "band_names" ) != NULL ||
    2318                 :         CSLFetchNameValue( poDS->papszHeader, "wavelength" ) != NULL)
    2319                 :     {
    2320                 :         char  **papszBandNames = 
    2321                 :             poDS->SplitList( CSLFetchNameValue( poDS->papszHeader, 
    2322              62 :                                                 "band_names" ) );
    2323                 :         char  **papszWL = 
    2324                 :             poDS->SplitList( CSLFetchNameValue( poDS->papszHeader, 
    2325              62 :                                                 "wavelength" ) );
    2326                 : 
    2327              62 :         const char *pszWLUnits = NULL;
    2328              62 :         int nWLCount = CSLCount(papszWL);
    2329              62 :         if (papszWL) 
    2330                 :         {
    2331                 :             /* If WL information is present, process wavelength units */
    2332                 :             pszWLUnits = CSLFetchNameValue( poDS->papszHeader, 
    2333               0 :                                             "wavelength_units" );
    2334               0 :             if (pszWLUnits)
    2335                 :             {
    2336                 :                 /* Don't show unknown or index units */
    2337               0 :                 if (EQUAL(pszWLUnits,"Unknown") ||
    2338                 :                     EQUAL(pszWLUnits,"Index") )
    2339               0 :                     pszWLUnits=0;
    2340                 :             }
    2341               0 :             if (pszWLUnits)
    2342                 :             {
    2343                 :                 /* set wavelength units to dataset metadata */
    2344               0 :                 poDS->SetMetadataItem("wavelength_units", pszWLUnits);
    2345                 :             }
    2346                 :         }
    2347                 : 
    2348             154 :         for( i = 0; i < nBands; i++ )
    2349                 :         {
    2350              92 :             CPLString osBandId, osBandName, osWavelength;
    2351                 : 
    2352                 :             /* First set up the wavelength names and units if available */
    2353              92 :             if (papszWL && nWLCount > i) 
    2354                 :             {
    2355               0 :                 osWavelength = papszWL[i];
    2356               0 :                 if (pszWLUnits) 
    2357                 :                 {
    2358               0 :                     osWavelength += " ";
    2359               0 :                     osWavelength += pszWLUnits;
    2360                 :                 }
    2361                 :             }
    2362                 : 
    2363                 :             /* Build the final name for this band */
    2364              92 :             if (papszBandNames && CSLCount(papszBandNames) > i)
    2365                 :             {
    2366              92 :                 osBandName = papszBandNames[i];
    2367              92 :                 if (strlen(osWavelength) > 0) 
    2368                 :                 {
    2369               0 :                     osBandName += " (";
    2370               0 :                     osBandName += osWavelength;
    2371               0 :                     osBandName += ")";
    2372                 :                 }
    2373                 :             }
    2374                 :             else   /* WL but no band names */
    2375               0 :                 osBandName = osWavelength;
    2376                 : 
    2377                 :             /* Description is for internal GDAL usage */
    2378              92 :             poDS->GetRasterBand(i + 1)->SetDescription( osBandName );
    2379                 : 
    2380                 :             /* Metadata field named Band_1, etc. needed for ArcGIS integration */
    2381              92 :             osBandId = CPLSPrintf("Band_%i", i+1);
    2382              92 :             poDS->SetMetadataItem(osBandId, osBandName);
    2383                 : 
    2384                 :             /* Set wavelength metadata to band */
    2385              92 :             if (papszWL && nWLCount > i)
    2386                 :             {
    2387                 :                 poDS->GetRasterBand(i+1)->SetMetadataItem(
    2388               0 :                     "wavelength", papszWL[i]);
    2389                 : 
    2390               0 :                 if (pszWLUnits)
    2391                 :                 {
    2392                 :                     poDS->GetRasterBand(i+1)->SetMetadataItem(
    2393               0 :                         "wavelength_units", pszWLUnits);
    2394                 :                 }
    2395                 :             }
    2396                 : 
    2397                 :         }
    2398              62 :         CSLDestroy( papszWL );
    2399              62 :         CSLDestroy( papszBandNames );
    2400                 :     }
    2401                 : /* -------------------------------------------------------------------- */
    2402                 : /*      Apply class names if we have them.                              */
    2403                 : /* -------------------------------------------------------------------- */
    2404             114 :     if( CSLFetchNameValue( poDS->papszHeader, "class_names" ) != NULL )
    2405                 :     {
    2406                 :         char  **papszClassNames = 
    2407                 :             poDS->SplitList( CSLFetchNameValue( poDS->papszHeader, 
    2408               3 :                                                 "class_names" ) );
    2409                 : 
    2410               3 :         poDS->GetRasterBand(1)->SetCategoryNames( papszClassNames );
    2411               3 :         CSLDestroy( papszClassNames );
    2412                 :     }
    2413                 :     
    2414                 : /* -------------------------------------------------------------------- */
    2415                 : /*      Apply colormap if we have one.          */
    2416                 : /* -------------------------------------------------------------------- */
    2417             114 :     if( CSLFetchNameValue( poDS->papszHeader, "class_lookup" ) != NULL )
    2418                 :     {
    2419                 :         char  **papszClassColors = 
    2420                 :             poDS->SplitList( CSLFetchNameValue( poDS->papszHeader, 
    2421               3 :                                                 "class_lookup" ) );
    2422               3 :         int nColorValueCount = CSLCount(papszClassColors);
    2423               3 :         GDALColorTable oCT;
    2424                 :     
    2425               9 :         for( i = 0; i*3+2 < nColorValueCount; i++ )
    2426                 :         {
    2427                 :             GDALColorEntry sEntry;
    2428                 : 
    2429               6 :             sEntry.c1 = (short) atoi(papszClassColors[i*3+0]);
    2430               6 :             sEntry.c2 = (short) atoi(papszClassColors[i*3+1]);
    2431               6 :             sEntry.c3 = (short) atoi(papszClassColors[i*3+2]);
    2432               6 :             sEntry.c4 = 255;
    2433               6 :             oCT.SetColorEntry( i, &sEntry );
    2434                 :         }
    2435                 : 
    2436               3 :         CSLDestroy( papszClassColors );
    2437                 : 
    2438               3 :         poDS->GetRasterBand(1)->SetColorTable( &oCT );
    2439               3 :         poDS->GetRasterBand(1)->SetColorInterpretation( GCI_PaletteIndex );
    2440                 :     }
    2441                 : 
    2442                 : /* -------------------------------------------------------------------- */
    2443                 : /*      Set the nodata value if it is present                           */
    2444                 : /* -------------------------------------------------------------------- */  
    2445             114 :     if( CSLFetchNameValue(poDS->papszHeader,"data_ignore_value" ) != NULL )
    2446                 :     {
    2447               0 :         for( i = 0; i < poDS->nBands; i++ )
    2448                 :             ((RawRasterBand*)poDS->GetRasterBand(i+1))->SetNoDataValue(atof(
    2449               0 :                                                                              CSLFetchNameValue(poDS->papszHeader,"data_ignore_value")));
    2450                 :     }
    2451                 : 
    2452                 : /* -------------------------------------------------------------------- */
    2453                 : /*      Set all the header metadata into the ENVI domain                */
    2454                 : /* -------------------------------------------------------------------- */  
    2455                 :     {
    2456             114 :         char** pTmp = poDS->papszHeader;
    2457            1387 :         while (*pTmp != NULL)
    2458                 :         {
    2459            1159 :             char** pTokens = CSLTokenizeString2(*pTmp, "=", CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
    2460            1159 :             if (pTokens[0] != NULL && pTokens[1] != NULL && pTokens[2] == NULL)
    2461                 :             {
    2462            1159 :                 poDS->SetMetadataItem(pTokens[0], pTokens[1], "ENVI");
    2463                 :             }
    2464            1159 :             CSLDestroy(pTokens);
    2465            1159 :             pTmp++;
    2466                 :         }
    2467                 :     } 
    2468                 : 
    2469                 : /* -------------------------------------------------------------------- */
    2470                 : /*      Read the stats file if it is present                            */
    2471                 : /* -------------------------------------------------------------------- */  
    2472             114 :     poDS->ProcessStatsFile();
    2473                 : 
    2474                 : /* -------------------------------------------------------------------- */
    2475                 : /*      Look for mapinfo                                                */
    2476                 : /* -------------------------------------------------------------------- */
    2477             114 :     if( CSLFetchNameValue( poDS->papszHeader, "map_info" ) != NULL )
    2478                 :     {
    2479                 :         poDS->bFoundMapinfo = 
    2480                 :             poDS->ProcessMapinfo( 
    2481              52 :                 CSLFetchNameValue(poDS->papszHeader,"map_info") );
    2482                 :     }
    2483                 : 
    2484                 : /* -------------------------------------------------------------------- */
    2485                 : /*      Look for RPC mapinfo                                            */
    2486                 : /* -------------------------------------------------------------------- */
    2487             114 :     if( !poDS->bFoundMapinfo &&
    2488                 :         CSLFetchNameValue( poDS->papszHeader, "rpc_info" ) != NULL )
    2489                 :     {
    2490                 :         poDS->ProcessRPCinfo( 
    2491                 :             CSLFetchNameValue(poDS->papszHeader,"rpc_info"), 
    2492               3 :             poDS->nRasterXSize, poDS->nRasterYSize);
    2493                 :     }
    2494                 :     
    2495                 : /* -------------------------------------------------------------------- */
    2496                 : /*      Initialize any PAM information.                                 */
    2497                 : /* -------------------------------------------------------------------- */
    2498             114 :     poDS->SetDescription( poOpenInfo->pszFilename );
    2499             114 :     poDS->TryLoadXML();
    2500                 : 
    2501                 : /* -------------------------------------------------------------------- */
    2502                 : /*      Check for overviews.                                            */
    2503                 : /* -------------------------------------------------------------------- */
    2504             114 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    2505                 : 
    2506             114 :     return( poDS );
    2507                 : }
    2508                 : 
    2509             183 : int ENVIDataset::GetEnviType(GDALDataType eType)
    2510                 : {
    2511                 :   int iENVIType;
    2512             183 :   switch( eType )
    2513                 :   {
    2514                 :       case GDT_Byte:
    2515              97 :         iENVIType = 1;
    2516              97 :         break;
    2517                 :       case GDT_Int16:
    2518              10 :         iENVIType = 2;
    2519              10 :         break;
    2520                 :       case GDT_Int32:
    2521              10 :         iENVIType = 3;
    2522              10 :         break;
    2523                 :       case GDT_Float32:
    2524              10 :         iENVIType = 4;
    2525              10 :         break;
    2526                 :       case GDT_Float64:
    2527              10 :         iENVIType = 5;
    2528              10 :         break;
    2529                 :       case GDT_CFloat32:
    2530               9 :         iENVIType = 6;
    2531               9 :         break;
    2532                 :       case GDT_CFloat64:
    2533               9 :         iENVIType = 9;
    2534               9 :         break;
    2535                 :       case GDT_UInt16:
    2536              10 :         iENVIType = 12;
    2537              10 :         break;
    2538                 :       case GDT_UInt32:
    2539              10 :         iENVIType = 13;
    2540              10 :         break;
    2541                 : 
    2542                 :   /* 14=Int64, 15=UInt64 */
    2543                 : 
    2544                 :       default:
    2545                 :         CPLError( CE_Failure, CPLE_AppDefined,
    2546                 :               "Attempt to create ENVI .hdr labelled dataset with an illegal\n"
    2547                 :               "data type (%s).\n",
    2548               8 :               GDALGetDataTypeName(eType) );
    2549               8 :         return 1;
    2550                 :   }
    2551             175 :   return iENVIType;
    2552                 : }
    2553                 : 
    2554                 : /************************************************************************/
    2555                 : /*                               Create()                               */
    2556                 : /************************************************************************/
    2557                 : 
    2558              69 : GDALDataset *ENVIDataset::Create( const char * pszFilename,
    2559                 :                                   int nXSize, int nYSize, int nBands,
    2560                 :                                   GDALDataType eType,
    2561                 :                                   char ** papszOptions )
    2562                 : 
    2563                 : {
    2564                 : /* -------------------------------------------------------------------- */
    2565                 : /*      Verify input options.                                           */
    2566                 : /* -------------------------------------------------------------------- */
    2567              69 :     int iENVIType = GetEnviType(eType);
    2568              69 :     if (0 == iENVIType)
    2569               0 :       return 0;
    2570                 : 
    2571                 : /* -------------------------------------------------------------------- */
    2572                 : /*      Try to create the file.                                         */
    2573                 : /* -------------------------------------------------------------------- */
    2574                 :     VSILFILE  *fp;
    2575                 : 
    2576              69 :     fp = VSIFOpenL( pszFilename, "wb" );
    2577                 : 
    2578              69 :     if( fp == NULL )
    2579                 :     {
    2580                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    2581                 :                   "Attempt to create file `%s' failed.\n",
    2582              17 :                   pszFilename );
    2583              17 :         return NULL;
    2584                 :     }
    2585                 : 
    2586                 : /* -------------------------------------------------------------------- */
    2587                 : /*      Just write out a couple of bytes to establish the binary        */
    2588                 : /*      file, and then close it.                                        */
    2589                 : /* -------------------------------------------------------------------- */
    2590              52 :     VSIFWriteL( (void *) "\0\0", 2, 1, fp );
    2591              52 :     VSIFCloseL( fp );
    2592                 : 
    2593                 : /* -------------------------------------------------------------------- */
    2594                 : /*      Create the .hdr filename.                                       */
    2595                 : /* -------------------------------------------------------------------- */
    2596                 :     const char  *pszHDRFilename;
    2597                 :     const char  *pszSuffix;
    2598                 : 
    2599              52 :     pszSuffix = CSLFetchNameValue( papszOptions, "SUFFIX" );
    2600              52 :     if ( pszSuffix && EQUALN( pszSuffix, "ADD", 3 ))
    2601               0 :   pszHDRFilename = CPLFormFilename( NULL, pszFilename, "hdr" );
    2602                 :     else
    2603              52 :   pszHDRFilename = CPLResetExtension(pszFilename, "hdr" );
    2604                 : 
    2605                 : /* -------------------------------------------------------------------- */
    2606                 : /*      Open the file.                                                  */
    2607                 : /* -------------------------------------------------------------------- */
    2608              52 :     fp = VSIFOpenL( pszHDRFilename, "wt" );
    2609              52 :     if( fp == NULL )
    2610                 :     {
    2611                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    2612                 :                   "Attempt to create file `%s' failed.\n",
    2613               0 :                   pszHDRFilename );
    2614               0 :         return NULL;
    2615                 :     }
    2616                 : 
    2617                 : /* -------------------------------------------------------------------- */
    2618                 : /*      Write out the header.                                           */
    2619                 : /* -------------------------------------------------------------------- */
    2620                 :     int   iBigEndian;
    2621                 :     const char  *pszInterleaving;
    2622                 :     
    2623                 : #ifdef CPL_LSB
    2624              52 :     iBigEndian = 0;
    2625                 : #else
    2626                 :     iBigEndian = 1;
    2627                 : #endif
    2628                 : 
    2629              52 :     VSIFPrintfL( fp, "ENVI\n" );
    2630                 :     VSIFPrintfL( fp, "samples = %d\nlines   = %d\nbands   = %d\n",
    2631              52 :     nXSize, nYSize, nBands );
    2632              52 :     VSIFPrintfL( fp, "header offset = 0\nfile type = ENVI Standard\n" );
    2633              52 :     VSIFPrintfL( fp, "data type = %d\n", iENVIType );
    2634              52 :     pszInterleaving = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
    2635              52 :     if ( pszInterleaving )
    2636                 :     {
    2637               0 :   if ( EQUALN( pszInterleaving, "bip", 3 ) )
    2638               0 :       pszInterleaving = "bip";        // interleaved by pixel
    2639               0 :   else if ( EQUALN( pszInterleaving, "bil", 3 ) )
    2640               0 :       pszInterleaving = "bil";        // interleaved by line
    2641                 :   else
    2642               0 :       pszInterleaving = "bsq";    // band sequental by default
    2643                 :     }
    2644                 :     else
    2645              52 :   pszInterleaving = "bsq";
    2646              52 :     VSIFPrintfL( fp, "interleave = %s\n", pszInterleaving);
    2647              52 :     VSIFPrintfL( fp, "byte order = %d\n", iBigEndian );
    2648                 : 
    2649              52 :     VSIFCloseL( fp );
    2650                 : 
    2651              52 :     return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
    2652                 : }
    2653                 : 
    2654                 : /************************************************************************/
    2655                 : /*                           ENVIRasterBand()                           */
    2656                 : /************************************************************************/
    2657                 : 
    2658             189 : ENVIRasterBand::ENVIRasterBand( GDALDataset *poDS, int nBand, void * fpRaw,
    2659                 :                                 vsi_l_offset nImgOffset, int nPixelOffset,
    2660                 :                                 int nLineOffset,
    2661                 :                                 GDALDataType eDataType, int bNativeOrder,
    2662                 :                                 int bIsVSIL, int bOwnsFP ) :
    2663                 :         RawRasterBand(poDS, nBand, fpRaw, nImgOffset, nPixelOffset,
    2664             189 :                       nLineOffset, eDataType, bNativeOrder, bIsVSIL, bOwnsFP)
    2665                 : {
    2666             189 : }
    2667                 : 
    2668                 : /************************************************************************/
    2669                 : /*                           SetDescription()                           */
    2670                 : /************************************************************************/
    2671                 : 
    2672              97 : void ENVIRasterBand::SetDescription( const char * pszDescription )
    2673                 : {
    2674              97 :     ((ENVIDataset*)poDS)->bHeaderDirty = TRUE;
    2675              97 :     RawRasterBand::SetDescription(pszDescription);
    2676              97 : }
    2677                 : 
    2678                 : /************************************************************************/
    2679                 : /*                           SetCategoryNames()                         */
    2680                 : /************************************************************************/
    2681                 : 
    2682               4 : CPLErr ENVIRasterBand::SetCategoryNames( char ** papszCategoryNames )
    2683                 : {
    2684               4 :     ((ENVIDataset*)poDS)->bHeaderDirty = TRUE;
    2685               4 :     return RawRasterBand::SetCategoryNames(papszCategoryNames);
    2686                 : }
    2687                 : 
    2688                 : /************************************************************************/
    2689                 : /*                         GDALRegister_ENVI()                          */
    2690                 : /************************************************************************/
    2691                 : 
    2692             610 : void GDALRegister_ENVI()
    2693                 : {
    2694                 :     GDALDriver  *poDriver;
    2695                 : 
    2696             610 :     if( GDALGetDriverByName( "ENVI" ) == NULL )
    2697                 :     {
    2698             588 :         poDriver = new GDALDriver();
    2699                 :         
    2700             588 :         poDriver->SetDescription( "ENVI" );
    2701                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    2702             588 :                                    "ENVI .hdr Labelled" );
    2703                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2704             588 :                                    "frmt_various.html#ENVI" );
    2705             588 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "" );
    2706                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2707                 :                                    "Byte Int16 UInt16 Int32 UInt32 "
    2708             588 :                                    "Float32 Float64 CFloat32 CFloat64" );
    2709                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    2710                 : "<CreationOptionList>"
    2711                 : "   <Option name='SUFFIX' type='string-select'>"
    2712                 : "       <Value>ADD</Value>"
    2713                 : "   </Option>"
    2714                 : "   <Option name='INTERLEAVE' type='string-select'>"
    2715                 : "       <Value>BIP</Value>"
    2716                 : "       <Value>BIL</Value>"
    2717                 : "       <Value>BSQ</Value>"
    2718                 : "   </Option>"
    2719             588 : "</CreationOptionList>" );
    2720                 : 
    2721             588 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2722             588 :         poDriver->pfnOpen = ENVIDataset::Open;
    2723             588 :         poDriver->pfnCreate = ENVIDataset::Create;
    2724                 : 
    2725             588 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2726                 :     }
    2727             610 : }

Generated by: LCOV version 1.7