LCOV - code coverage report
Current view: directory - frmts/raw - envidataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 851 481 56.5 %
Date: 2010-01-09 Functions: 26 21 80.8 %

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

Generated by: LCOV version 1.7