LCOV - code coverage report
Current view: directory - frmts/ers - ersdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 531 442 83.2 %
Date: 2012-12-26 Functions: 31 26 83.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: ersdataset.cpp 24927 2012-09-16 12:14:44Z rouault $
       3                 :  *
       4                 :  * Project:  ERMapper .ers Driver
       5                 :  * Purpose:  Implementation of .ers driver.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "rawdataset.h"
      31                 : #include "ogr_spatialref.h"
      32                 : #include "cpl_string.h"
      33                 : #include "ershdrnode.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ersdataset.cpp 24927 2012-09-16 12:14:44Z rouault $");
      36                 : 
      37                 : /************************************************************************/
      38                 : /* ==================================================================== */
      39                 : /*                              ERSDataset                              */
      40                 : /* ==================================================================== */
      41                 : /************************************************************************/
      42                 : 
      43                 : class ERSRasterBand;
      44                 : 
      45                 : class ERSDataset : public RawDataset
      46                 : {
      47                 :     friend class ERSRasterBand;
      48                 : 
      49                 :     VSILFILE  *fpImage; // image data file.
      50                 :     GDALDataset *poDepFile;
      51                 : 
      52                 :     int         bGotTransform;
      53                 :     double      adfGeoTransform[6];
      54                 :     char       *pszProjection;
      55                 : 
      56                 :     CPLString   osRawFilename;
      57                 : 
      58                 :     int         bHDRDirty;
      59                 :     ERSHdrNode *poHeader;
      60                 : 
      61                 :     const char *Find( const char *, const char * );
      62                 : 
      63                 :     int           nGCPCount;
      64                 :     GDAL_GCP      *pasGCPList;
      65                 :     char          *pszGCPProjection;
      66                 : 
      67                 :     void          ReadGCPs();
      68                 : 
      69                 :     int         bHasNoDataValue;
      70                 :     double      dfNoDataValue;
      71                 : 
      72                 :     CPLString      osProj;
      73                 :     CPLString      osDatum;
      74                 :     CPLString      osUnits;
      75                 :     void           WriteProjectionInfo(const char* pszProj,
      76                 :                                        const char* pszDatum,
      77                 :                                        const char* pszUnits);
      78                 : 
      79                 :     CPLStringList oERSMetadataList;
      80                 : 
      81                 :   protected:
      82                 :     virtual int         CloseDependentDatasets();
      83                 : 
      84                 :   public:
      85                 :         ERSDataset();
      86                 :          ~ERSDataset();
      87                 :     
      88                 :     virtual void FlushCache(void);
      89                 :     virtual CPLErr GetGeoTransform( double * padfTransform );
      90                 :     virtual CPLErr SetGeoTransform( double *padfTransform );
      91                 :     virtual const char *GetProjectionRef(void);
      92                 :     virtual CPLErr SetProjection( const char * );
      93                 :     virtual char **GetFileList(void);
      94                 :     
      95                 :     virtual int    GetGCPCount();
      96                 :     virtual const char *GetGCPProjection();
      97                 :     virtual const GDAL_GCP *GetGCPs();
      98                 :     virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
      99                 :                             const char *pszGCPProjection );
     100                 : 
     101                 :     virtual const char *GetMetadataItem( const char * pszName,
     102                 :                                      const char * pszDomain = "" );
     103                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
     104                 : 
     105                 :     static GDALDataset *Open( GDALOpenInfo * );
     106                 :     static int Identify( GDALOpenInfo * );
     107                 :     static GDALDataset *Create( const char * pszFilename,
     108                 :                                 int nXSize, int nYSize, int nBands,
     109                 :                                 GDALDataType eType, char ** papszParmList );
     110                 : };
     111                 : 
     112                 : /************************************************************************/
     113                 : /*                            ERSDataset()                             */
     114                 : /************************************************************************/
     115                 : 
     116              50 : ERSDataset::ERSDataset()
     117                 : {
     118              50 :     fpImage = NULL;
     119              50 :     poDepFile = NULL;
     120              50 :     pszProjection = CPLStrdup("");
     121              50 :     bGotTransform = FALSE;
     122              50 :     adfGeoTransform[0] = 0.0;
     123              50 :     adfGeoTransform[1] = 1.0;
     124              50 :     adfGeoTransform[2] = 0.0;
     125              50 :     adfGeoTransform[3] = 0.0;
     126              50 :     adfGeoTransform[4] = 0.0;
     127              50 :     adfGeoTransform[5] = 1.0;
     128              50 :     poHeader = NULL;
     129              50 :     bHDRDirty = FALSE;
     130                 : 
     131              50 :     nGCPCount = 0;
     132              50 :     pasGCPList = NULL;
     133              50 :     pszGCPProjection = CPLStrdup("");
     134                 : 
     135              50 :     bHasNoDataValue = FALSE;
     136              50 :     dfNoDataValue = 0.0;
     137              50 : }
     138                 : 
     139                 : /************************************************************************/
     140                 : /*                            ~ERSDataset()                            */
     141                 : /************************************************************************/
     142                 : 
     143              50 : ERSDataset::~ERSDataset()
     144                 : 
     145                 : {
     146              50 :     FlushCache();
     147                 : 
     148              50 :     if( fpImage != NULL )
     149                 :     {
     150              50 :         VSIFCloseL( fpImage );
     151                 :     }
     152                 : 
     153              50 :     CloseDependentDatasets();
     154                 : 
     155              50 :     CPLFree( pszProjection );
     156                 : 
     157              50 :     CPLFree( pszGCPProjection );
     158              50 :     if( nGCPCount > 0 )
     159                 :     {
     160               3 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     161               3 :         CPLFree( pasGCPList );
     162                 :     }
     163                 : 
     164              50 :     if( poHeader != NULL )
     165              50 :         delete poHeader;
     166              50 : }
     167                 : 
     168                 : /************************************************************************/
     169                 : /*                      CloseDependentDatasets()                        */
     170                 : /************************************************************************/
     171                 : 
     172              50 : int ERSDataset::CloseDependentDatasets()
     173                 : {
     174              50 :     int bHasDroppedRef = RawDataset::CloseDependentDatasets();
     175                 : 
     176              50 :     if( poDepFile != NULL )
     177                 :     {
     178                 :         int iBand;
     179                 : 
     180               0 :         bHasDroppedRef = TRUE;
     181                 : 
     182               0 :         for( iBand = 0; iBand < nBands; iBand++ )
     183               0 :             papoBands[iBand] = NULL;
     184               0 :         nBands = 0;
     185                 : 
     186               0 :         GDALClose( (GDALDatasetH) poDepFile );
     187               0 :         poDepFile = NULL;
     188                 :     }
     189                 : 
     190              50 :     return bHasDroppedRef;
     191                 : }
     192                 : 
     193                 : /************************************************************************/
     194                 : /*                             FlushCache()                             */
     195                 : /************************************************************************/
     196                 : 
     197              50 : void ERSDataset::FlushCache()
     198                 : 
     199                 : {
     200              50 :     if( bHDRDirty )
     201                 :     {
     202              33 :         VSILFILE * fpERS = VSIFOpenL( GetDescription(), "w" );
     203              33 :         if( fpERS == NULL )
     204                 :         {
     205                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     206                 :                       "Unable to rewrite %s header.",
     207               0 :                       GetDescription() );
     208                 :         }
     209                 :         else
     210                 :         {
     211              33 :             VSIFPrintfL( fpERS, "DatasetHeader Begin\n" );
     212              33 :             poHeader->WriteSelf( fpERS, 1 );
     213              33 :             VSIFPrintfL( fpERS, "DatasetHeader End\n" );
     214              33 :             VSIFCloseL( fpERS );
     215                 :         }
     216                 :     }
     217                 : 
     218              50 :     RawDataset::FlushCache();
     219              50 : }
     220                 : 
     221                 : /************************************************************************/
     222                 : /*                           GetMetadataItem()                          */
     223                 : /************************************************************************/
     224                 : 
     225              47 : const char *ERSDataset::GetMetadataItem( const char * pszName,
     226                 :                                          const char * pszDomain )
     227                 : {
     228              47 :     if (pszDomain != NULL && EQUAL(pszDomain, "ERS") && pszName != NULL)
     229                 :     {
     230               3 :         if (EQUAL(pszName, "PROJ"))
     231               1 :             return osProj.size() ? osProj.c_str() : NULL;
     232               2 :         if (EQUAL(pszName, "DATUM"))
     233               1 :             return osDatum.size() ? osDatum.c_str() : NULL;
     234               1 :         if (EQUAL(pszName, "UNITS"))
     235               1 :             return osUnits.size() ? osUnits.c_str() : NULL;
     236                 :     }
     237              44 :     return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
     238                 : }
     239                 : 
     240                 : /************************************************************************/
     241                 : /*                            GetMetadata()                             */
     242                 : /************************************************************************/
     243                 : 
     244               3 : char **ERSDataset::GetMetadata( const char *pszDomain )
     245                 : 
     246                 : {
     247               3 :     if( pszDomain != NULL && EQUAL(pszDomain, "ERS") )
     248                 :     {
     249               1 :         oERSMetadataList.Clear();
     250               1 :         if (osProj.size())
     251               1 :             oERSMetadataList.AddString(CPLSPrintf("%s=%s", "PROJ", osProj.c_str()));
     252               1 :         if (osDatum.size())
     253               1 :             oERSMetadataList.AddString(CPLSPrintf("%s=%s", "DATUM", osDatum.c_str()));
     254               1 :         if (osUnits.size())
     255               1 :             oERSMetadataList.AddString(CPLSPrintf("%s=%s", "UNITS", osUnits.c_str()));
     256               1 :         return oERSMetadataList.List();
     257                 :     }
     258                 :     else
     259               2 :         return GDALPamDataset::GetMetadata( pszDomain );
     260                 : }
     261                 : 
     262                 : /************************************************************************/
     263                 : /*                            GetGCPCount()                             */
     264                 : /************************************************************************/
     265                 : 
     266               3 : int ERSDataset::GetGCPCount()
     267                 : 
     268                 : {
     269               3 :     return nGCPCount;
     270                 : }
     271                 : 
     272                 : /************************************************************************/
     273                 : /*                          GetGCPProjection()                          */
     274                 : /************************************************************************/
     275                 : 
     276               1 : const char *ERSDataset::GetGCPProjection()
     277                 : 
     278                 : {
     279               1 :     return pszGCPProjection;
     280                 : }
     281                 : 
     282                 : /************************************************************************/
     283                 : /*                               GetGCPs()                              */
     284                 : /************************************************************************/
     285                 : 
     286               1 : const GDAL_GCP *ERSDataset::GetGCPs()
     287                 : 
     288                 : {
     289               1 :     return pasGCPList;
     290                 : }
     291                 : 
     292                 : /************************************************************************/
     293                 : /*                              SetGCPs()                               */
     294                 : /************************************************************************/
     295                 : 
     296               1 : CPLErr ERSDataset::SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
     297                 :                             const char *pszGCPProjectionIn )
     298                 : 
     299                 : {
     300                 : /* -------------------------------------------------------------------- */
     301                 : /*      Clean old gcps.                                                 */
     302                 : /* -------------------------------------------------------------------- */
     303               1 :     CPLFree( pszGCPProjection );
     304               1 :     pszGCPProjection = NULL;
     305                 : 
     306               1 :     if( nGCPCount > 0 )
     307                 :     {
     308               0 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     309               0 :         CPLFree( pasGCPList );
     310                 : 
     311               0 :         pasGCPList = NULL;
     312               0 :         nGCPCount = 0;
     313                 :     }
     314                 : 
     315                 : /* -------------------------------------------------------------------- */
     316                 : /*      Copy new ones.                                                  */
     317                 : /* -------------------------------------------------------------------- */
     318               1 :     nGCPCount = nGCPCountIn;
     319               1 :     pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPListIn );
     320               1 :     pszGCPProjection = CPLStrdup( pszGCPProjectionIn );
     321                 : 
     322                 : /* -------------------------------------------------------------------- */
     323                 : /*      Setup the header contents corresponding to these GCPs.          */
     324                 : /* -------------------------------------------------------------------- */
     325               1 :     bHDRDirty = TRUE;
     326                 : 
     327               1 :     poHeader->Set( "RasterInfo.WarpControl.WarpType", "Polynomial" );
     328               1 :     if( nGCPCount > 6 )
     329               0 :         poHeader->Set( "RasterInfo.WarpControl.WarpOrder", "2" );
     330                 :     else
     331               1 :         poHeader->Set( "RasterInfo.WarpControl.WarpOrder", "1" );
     332               1 :     poHeader->Set( "RasterInfo.WarpControl.WarpSampling", "Nearest" );
     333                 : 
     334                 : /* -------------------------------------------------------------------- */
     335                 : /*      Translate the projection.                                       */
     336                 : /* -------------------------------------------------------------------- */
     337               1 :     OGRSpatialReference oSRS( pszGCPProjection );
     338                 :     char szERSProj[32], szERSDatum[32], szERSUnits[32];
     339                 : 
     340               1 :     oSRS.exportToERM( szERSProj, szERSDatum, szERSUnits );
     341                 : 
     342                 :     /* Write the above computed values, unless they have been overriden by */
     343                 :     /* the creation options PROJ, DATUM or UNITS */
     344                 : 
     345                 :     poHeader->Set( "RasterInfo.WarpControl.CoordinateSpace.Datum", 
     346                 :                    CPLString().Printf( "\"%s\"",
     347               1 :                         (osDatum.size()) ? osDatum.c_str() : szERSDatum ) );
     348                 :     poHeader->Set( "RasterInfo.WarpControl.CoordinateSpace.Projection", 
     349                 :                    CPLString().Printf( "\"%s\"",
     350               1 :                         (osProj.size()) ? osProj.c_str() : szERSProj ) );
     351                 :     poHeader->Set( "RasterInfo.WarpControl.CoordinateSpace.CoordinateType", 
     352               1 :                    CPLString().Printf( "EN" ) );
     353                 :     poHeader->Set( "RasterInfo.WarpControl.CoordinateSpace.Units", 
     354                 :                    CPLString().Printf( "\"%s\"",
     355               1 :                         (osUnits.size()) ? osUnits.c_str() : szERSUnits ) );
     356                 :     poHeader->Set( "RasterInfo.WarpControl.CoordinateSpace.Rotation", 
     357               1 :                    "0:0:0.0" );
     358                 : 
     359                 : /* -------------------------------------------------------------------- */
     360                 : /*      Translate the GCPs.                                             */
     361                 : /* -------------------------------------------------------------------- */
     362               1 :     CPLString osControlPoints = "{\n";
     363                 :     int iGCP;
     364                 :     
     365               5 :     for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
     366                 :     {
     367               4 :         CPLString osLine;
     368                 : 
     369               4 :         CPLString osId = pasGCPList[iGCP].pszId;
     370               4 :         if( strlen(osId) == 0 )
     371               4 :             osId.Printf( "%d", iGCP + 1 );
     372                 : 
     373                 :         osLine.Printf( "\t\t\t\t\"%s\"\tYes\tYes\t%.6f\t%.6f\t%.15g\t%.15g\t%.15g\n",
     374                 :                        osId.c_str(),
     375               4 :                        pasGCPList[iGCP].dfGCPPixel,
     376               4 :                        pasGCPList[iGCP].dfGCPLine,
     377               4 :                        pasGCPList[iGCP].dfGCPX,
     378               4 :                        pasGCPList[iGCP].dfGCPY,
     379              20 :                        pasGCPList[iGCP].dfGCPZ );
     380               4 :         osControlPoints += osLine;
     381                 :     }
     382               1 :     osControlPoints += "\t\t}";
     383                 :     
     384               1 :     poHeader->Set( "RasterInfo.WarpControl.ControlPoints", osControlPoints );
     385                 : 
     386               1 :     return CE_None;
     387                 : }
     388                 : 
     389                 : /************************************************************************/
     390                 : /*                          GetProjectionRef()                          */
     391                 : /************************************************************************/
     392                 : 
     393               5 : const char *ERSDataset::GetProjectionRef()
     394                 : 
     395                 : {
     396                 :     // try xml first
     397               5 :     const char* pszPrj = GDALPamDataset::GetProjectionRef();
     398               5 :     if(pszPrj && strlen(pszPrj) > 0)
     399               0 :         return pszPrj;
     400                 : 
     401               5 :     return pszProjection;
     402                 : }
     403                 : 
     404                 : /************************************************************************/
     405                 : /*                           SetProjection()                            */
     406                 : /************************************************************************/
     407                 : 
     408              31 : CPLErr ERSDataset::SetProjection( const char *pszSRS )
     409                 : 
     410                 : {
     411              31 :     if( pszProjection && EQUAL(pszSRS,pszProjection) )
     412               0 :         return CE_None;
     413                 : 
     414              31 :     if( pszSRS == NULL )
     415               0 :         pszSRS = "";
     416                 : 
     417              31 :     CPLFree( pszProjection );
     418              31 :     pszProjection = CPLStrdup(pszSRS);
     419                 : 
     420              31 :     OGRSpatialReference oSRS( pszSRS );
     421                 :     char szERSProj[32], szERSDatum[32], szERSUnits[32];
     422                 : 
     423              31 :     oSRS.exportToERM( szERSProj, szERSDatum, szERSUnits );
     424                 : 
     425                 :     /* Write the above computed values, unless they have been overriden by */
     426                 :     /* the creation options PROJ, DATUM or UNITS */
     427                 :     WriteProjectionInfo( (osProj.size()) ? osProj.c_str() : szERSProj,
     428                 :                          (osDatum.size()) ? osDatum.c_str() : szERSDatum,
     429              31 :                          (osUnits.size()) ? osUnits.c_str() : szERSUnits );
     430                 : 
     431              31 :     return CE_None;
     432                 : }
     433                 : 
     434                 : /************************************************************************/
     435                 : /*                         WriteProjectionInfo()                        */
     436                 : /************************************************************************/
     437                 : 
     438              32 : void ERSDataset::WriteProjectionInfo(const char* pszProj,
     439                 :                                      const char* pszDatum,
     440                 :                                      const char* pszUnits)
     441                 : {
     442              32 :     bHDRDirty = TRUE;
     443                 :     poHeader->Set( "CoordinateSpace.Datum", 
     444              32 :                    CPLString().Printf( "\"%s\"", pszDatum ) );
     445                 :     poHeader->Set( "CoordinateSpace.Projection", 
     446              64 :                    CPLString().Printf( "\"%s\"", pszProj ) );
     447                 :     poHeader->Set( "CoordinateSpace.CoordinateType", 
     448              64 :                    CPLString().Printf( "EN" ) );
     449                 :     poHeader->Set( "CoordinateSpace.Units", 
     450              64 :                    CPLString().Printf( "\"%s\"", pszUnits ) );
     451                 :     poHeader->Set( "CoordinateSpace.Rotation", 
     452              32 :                    "0:0:0.0" );
     453                 : 
     454                 : /* -------------------------------------------------------------------- */
     455                 : /*      It seems that CoordinateSpace needs to come before              */
     456                 : /*      RasterInfo.  Try moving it up manually.                         */
     457                 : /* -------------------------------------------------------------------- */
     458              32 :     int iRasterInfo = -1;
     459              32 :     int iCoordSpace = -1;
     460                 :     int i;
     461                 : 
     462             223 :     for( i = 0; i < poHeader->nItemCount; i++ )
     463                 :     {
     464             223 :         if( EQUAL(poHeader->papszItemName[i],"RasterInfo") )
     465              31 :             iRasterInfo = i;
     466                 : 
     467             223 :         if( EQUAL(poHeader->papszItemName[i],"CoordinateSpace") )
     468                 :         {
     469              32 :             iCoordSpace = i;
     470              32 :             break;
     471                 :         }
     472                 :     }
     473                 : 
     474              32 :     if( iCoordSpace > iRasterInfo && iRasterInfo != -1 )
     475                 :     {
     476              62 :         for( i = iCoordSpace; i > 0 && i != iRasterInfo; i-- )
     477                 :         {
     478                 :             char *pszTemp;
     479                 : 
     480              31 :             ERSHdrNode *poTemp = poHeader->papoItemChild[i];
     481              31 :             poHeader->papoItemChild[i] = poHeader->papoItemChild[i-1];
     482              31 :             poHeader->papoItemChild[i-1] = poTemp;
     483                 : 
     484              31 :             pszTemp = poHeader->papszItemName[i];
     485              31 :             poHeader->papszItemName[i] = poHeader->papszItemName[i-1];
     486              31 :             poHeader->papszItemName[i-1] = pszTemp;
     487                 : 
     488              31 :             pszTemp = poHeader->papszItemValue[i];
     489              31 :             poHeader->papszItemValue[i] = poHeader->papszItemValue[i-1];
     490              31 :             poHeader->papszItemValue[i-1] = pszTemp;
     491                 :         }
     492                 :     }
     493              32 : }
     494                 : 
     495                 : /************************************************************************/
     496                 : /*                          GetGeoTransform()                           */
     497                 : /************************************************************************/
     498                 : 
     499              20 : CPLErr ERSDataset::GetGeoTransform( double * padfTransform )
     500                 : 
     501                 : {
     502              20 :     if( bGotTransform )
     503                 :     {
     504              20 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
     505              20 :         return CE_None;
     506                 :     }
     507                 :     else
     508                 :     {
     509               0 :         return GDALPamDataset::GetGeoTransform( padfTransform );
     510                 :     }
     511                 : }
     512                 : 
     513                 : /************************************************************************/
     514                 : /*                          SetGeoTransform()                           */
     515                 : /************************************************************************/
     516                 : 
     517              30 : CPLErr ERSDataset::SetGeoTransform( double *padfTransform )
     518                 : 
     519                 : {
     520              30 :     if( memcmp( padfTransform, adfGeoTransform, sizeof(double)*6 ) == 0 )
     521               0 :         return CE_None;
     522                 : 
     523              30 :     if( adfGeoTransform[2] != 0 || adfGeoTransform[4] != 0 )
     524                 :     {
     525                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     526               0 :                   "Rotated and skewed geotransforms not currently supported for ERS driver." );
     527               0 :         return CE_Failure;
     528                 :     }
     529                 : 
     530              30 :     bGotTransform = TRUE;
     531              30 :     memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
     532                 : 
     533              30 :     bHDRDirty = TRUE;
     534                 : 
     535                 :     poHeader->Set( "RasterInfo.CellInfo.Xdimension", 
     536              30 :                    CPLString().Printf( "%.15g", fabs(adfGeoTransform[1]) ) );
     537                 :     poHeader->Set( "RasterInfo.CellInfo.Ydimension", 
     538              60 :                    CPLString().Printf( "%.15g", fabs(adfGeoTransform[5]) ) );
     539                 :     poHeader->Set( "RasterInfo.RegistrationCoord.Eastings", 
     540              60 :                    CPLString().Printf( "%.15g", adfGeoTransform[0] ) );
     541                 :     poHeader->Set( "RasterInfo.RegistrationCoord.Northings", 
     542              60 :                    CPLString().Printf( "%.15g", adfGeoTransform[3] ) );
     543                 :     
     544              30 :     return CE_None;
     545                 : }
     546                 : 
     547                 : /************************************************************************/
     548                 : /*                             ERSDMS2Dec()                             */
     549                 : /*                                                                      */
     550                 : /*      Convert ERS DMS format to decimal degrees.   Input is like      */
     551                 : /*      "-180:00:00".                                                   */
     552                 : /************************************************************************/
     553                 : 
     554               4 : static double ERSDMS2Dec( const char *pszDMS )
     555                 : 
     556                 : {
     557               4 :     char **papszTokens = CSLTokenizeStringComplex( pszDMS, ":", FALSE, FALSE );
     558                 : 
     559               4 :     if( CSLCount(papszTokens) != 3 )
     560                 :     {
     561               0 :         CSLDestroy(papszTokens);
     562               0 :         return CPLAtof( pszDMS );
     563                 :     }
     564                 :     else
     565                 :     {
     566               4 :         double dfResult = fabs(CPLAtof(papszTokens[0]))
     567               4 :             + CPLAtof(papszTokens[1]) / 60.0
     568               8 :             + CPLAtof(papszTokens[2]) / 3600.0;
     569                 : 
     570               4 :         if( CPLAtof(papszTokens[0]) < 0 )
     571               3 :             dfResult *= -1;
     572                 : 
     573               4 :         CSLDestroy( papszTokens );
     574               4 :         return dfResult;
     575                 :     }
     576                 : }
     577                 : 
     578                 : /************************************************************************/
     579                 : /*                            GetFileList()                             */
     580                 : /************************************************************************/
     581                 : 
     582               6 : char **ERSDataset::GetFileList()
     583                 : 
     584                 : {
     585               6 :     char **papszFileList = NULL;
     586                 : 
     587                 :     // Main data file, etc. 
     588               6 :     papszFileList = GDALPamDataset::GetFileList();
     589                 : 
     590                 :     // Add raw data file if we have one. 
     591               6 :     if( strlen(osRawFilename) > 0 )
     592               6 :         papszFileList = CSLAddString( papszFileList, osRawFilename );
     593                 : 
     594                 :     // If we have a dependent file, merge it's list of files in. 
     595               6 :     if( poDepFile )
     596                 :     {
     597               0 :         char **papszDepFiles = poDepFile->GetFileList();
     598                 :         papszFileList = 
     599               0 :             CSLInsertStrings( papszFileList, -1, papszDepFiles );
     600               0 :         CSLDestroy( papszDepFiles );
     601                 :     }
     602                 : 
     603               6 :     return papszFileList;
     604                 : }
     605                 : 
     606                 : /************************************************************************/
     607                 : /*                              ReadGCPs()                              */
     608                 : /*                                                                      */
     609                 : /*      Read the GCPs from the header.                                  */
     610                 : /************************************************************************/
     611                 : 
     612               2 : void ERSDataset::ReadGCPs()
     613                 : 
     614                 : {
     615                 :     const char *pszCP = 
     616               2 :         poHeader->Find( "RasterInfo.WarpControl.ControlPoints", NULL );
     617                 : 
     618               2 :     if( pszCP == NULL )
     619               0 :         return;
     620                 : 
     621                 : /* -------------------------------------------------------------------- */
     622                 : /*      Parse the control points.  They will look something like:       */
     623                 : /*                                                                      */
     624                 : /*   "1035" Yes No 2344.650885 3546.419458 483270.73 3620906.21 3.105   */
     625                 : /* -------------------------------------------------------------------- */
     626               2 :     char **papszTokens = CSLTokenizeStringComplex( pszCP, "{ \t}", TRUE,FALSE);
     627                 :     int nItemsPerLine;
     628               2 :     int nItemCount = CSLCount(papszTokens);
     629                 : 
     630                 : /* -------------------------------------------------------------------- */
     631                 : /*      Work out if we have elevation values or not.                    */
     632                 : /* -------------------------------------------------------------------- */
     633               2 :     if( nItemCount == 7 )
     634               0 :         nItemsPerLine = 7;
     635               2 :     else if( nItemCount == 8 )
     636               0 :         nItemsPerLine = 8;
     637               2 :     else if( nItemCount < 14 )
     638                 :     {
     639               0 :         CPLDebug("ERS", "Invalid item count for ControlPoints");
     640               0 :         CSLDestroy( papszTokens );
     641               0 :         return;
     642                 :     }
     643               2 :     else if( EQUAL(papszTokens[8],"Yes") || EQUAL(papszTokens[8],"No") )
     644               0 :         nItemsPerLine = 7;
     645               4 :     else if( EQUAL(papszTokens[9],"Yes") || EQUAL(papszTokens[9],"No") )
     646               2 :         nItemsPerLine = 8;
     647                 :     else
     648                 :     {
     649               0 :         CPLDebug("ERS", "Invalid format for ControlPoints");
     650               0 :         CSLDestroy( papszTokens );
     651               0 :         return;
     652                 :     }
     653                 : 
     654                 : /* -------------------------------------------------------------------- */
     655                 : /*      Setup GCPs.                                                     */
     656                 : /* -------------------------------------------------------------------- */
     657                 :     int iGCP;
     658                 : 
     659               2 :     CPLAssert( nGCPCount == 0 );
     660                 : 
     661               2 :     nGCPCount = nItemCount / nItemsPerLine;
     662               2 :     pasGCPList = (GDAL_GCP *) CPLCalloc(nGCPCount,sizeof(GDAL_GCP));
     663               2 :     GDALInitGCPs( nGCPCount, pasGCPList );
     664                 : 
     665              10 :     for( iGCP = 0; iGCP < nGCPCount; iGCP++ )
     666                 :     {
     667               8 :         GDAL_GCP *psGCP = pasGCPList + iGCP;
     668                 : 
     669               8 :         CPLFree( psGCP->pszId );
     670               8 :         psGCP->pszId = CPLStrdup(papszTokens[iGCP*nItemsPerLine+0]);
     671               8 :         psGCP->dfGCPPixel = atof(papszTokens[iGCP*nItemsPerLine+3]);
     672               8 :         psGCP->dfGCPLine  = atof(papszTokens[iGCP*nItemsPerLine+4]);
     673               8 :         psGCP->dfGCPX     = atof(papszTokens[iGCP*nItemsPerLine+5]);
     674               8 :         psGCP->dfGCPY     = atof(papszTokens[iGCP*nItemsPerLine+6]);
     675               8 :         if( nItemsPerLine == 8 )
     676               8 :             psGCP->dfGCPZ = atof(papszTokens[iGCP*nItemsPerLine+7]);
     677                 :     }
     678                 :     
     679               2 :     CSLDestroy( papszTokens );
     680                 :     
     681                 : /* -------------------------------------------------------------------- */
     682                 : /*      Parse the GCP projection.                                       */
     683                 : /* -------------------------------------------------------------------- */
     684               2 :     OGRSpatialReference oSRS;
     685                 : 
     686               2 :     osProj = poHeader->Find( "RasterInfo.WarpControl.CoordinateSpace.Projection", "" );
     687               2 :     osDatum = poHeader->Find( "RasterInfo.WarpControl.CoordinateSpace.Datum", "" );
     688               2 :     osUnits = poHeader->Find( "RasterInfo.WarpControl.CoordinateSpace.Units", "" );
     689                 : 
     690                 :     oSRS.importFromERM( osProj.size() ? osProj.c_str() : "RAW",
     691                 :                         osDatum.size() ? osDatum.c_str() : "WGS84",
     692               2 :                         osUnits.size() ? osUnits.c_str() : "METERS" );
     693                 : 
     694               2 :     CPLFree( pszGCPProjection );
     695               2 :     oSRS.exportToWkt( &pszGCPProjection );
     696                 : }
     697                 : 
     698                 : /************************************************************************/
     699                 : /* ==================================================================== */
     700                 : /*                             ERSRasterBand                            */
     701                 : /* ==================================================================== */
     702                 : /************************************************************************/
     703                 : 
     704                 : class ERSRasterBand : public RawRasterBand
     705              90 : {
     706                 :     public:
     707                 : 
     708                 :                  ERSRasterBand( GDALDataset *poDS, int nBand, void * fpRaw,
     709                 :                                 vsi_l_offset nImgOffset, int nPixelOffset,
     710                 :                                 int nLineOffset,
     711                 :                                 GDALDataType eDataType, int bNativeOrder,
     712                 :                                 int bIsVSIL = FALSE, int bOwnsFP = FALSE );
     713                 : 
     714                 :     virtual double GetNoDataValue( int *pbSuccess = NULL );
     715                 :     virtual CPLErr SetNoDataValue( double );
     716                 : };
     717                 : 
     718                 : /************************************************************************/
     719                 : /*                           ERSRasterBand()                            */
     720                 : /************************************************************************/
     721                 : 
     722              90 : ERSRasterBand::ERSRasterBand( GDALDataset *poDS, int nBand, void * fpRaw,
     723                 :                                 vsi_l_offset nImgOffset, int nPixelOffset,
     724                 :                                 int nLineOffset,
     725                 :                                 GDALDataType eDataType, int bNativeOrder,
     726                 :                                 int bIsVSIL, int bOwnsFP ) :
     727                 :     RawRasterBand(poDS, nBand, fpRaw, nImgOffset, nPixelOffset,
     728              90 :                   nLineOffset, eDataType, bNativeOrder, bIsVSIL, bOwnsFP)
     729                 : {
     730              90 : }
     731                 : 
     732                 : /************************************************************************/
     733                 : /*                           GetNoDataValue()                           */
     734                 : /************************************************************************/
     735                 : 
     736              11 : double ERSRasterBand::GetNoDataValue( int *pbSuccess )
     737                 : {
     738              11 :     ERSDataset* poGDS = (ERSDataset*) poDS;
     739              11 :     if (poGDS->bHasNoDataValue)
     740                 :     {
     741               1 :         if (pbSuccess)
     742               1 :             *pbSuccess = TRUE;
     743               1 :         return poGDS->dfNoDataValue;
     744                 :     }
     745                 : 
     746              10 :     return RawRasterBand::GetNoDataValue(pbSuccess);
     747                 : }
     748                 : 
     749                 : /************************************************************************/
     750                 : /*                           SetNoDataValue()                           */
     751                 : /************************************************************************/
     752                 : 
     753               1 : CPLErr ERSRasterBand::SetNoDataValue( double dfNoDataValue )
     754                 : {
     755               1 :     ERSDataset* poGDS = (ERSDataset*) poDS;
     756               1 :     if (!poGDS->bHasNoDataValue || poGDS->dfNoDataValue != dfNoDataValue)
     757                 :     {
     758               1 :         poGDS->bHasNoDataValue = TRUE;
     759               1 :         poGDS->dfNoDataValue = dfNoDataValue;
     760                 : 
     761               1 :         poGDS->bHDRDirty = TRUE;
     762                 :         poGDS->poHeader->Set( "RasterInfo.NullCellValue",
     763               1 :                     CPLString().Printf( "%.16g", dfNoDataValue) );
     764                 :     }
     765               1 :     return CE_None;
     766                 : }
     767                 : 
     768                 : /************************************************************************/
     769                 : /*                              Identify()                              */
     770                 : /************************************************************************/
     771                 : 
     772           12752 : int ERSDataset::Identify( GDALOpenInfo * poOpenInfo )
     773                 : 
     774                 : {
     775                 : /* -------------------------------------------------------------------- */
     776                 : /*      We assume the user selects the .ers file.                       */
     777                 : /* -------------------------------------------------------------------- */
     778           12752 :     if( poOpenInfo->nHeaderBytes > 15
     779                 :         && EQUALN((const char *) poOpenInfo->pabyHeader,"Algorithm Begin",15) )
     780                 :     {
     781                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     782                 :                   "%s appears to be an algorithm ERS file, which is not currently supported.",
     783               0 :                   poOpenInfo->pszFilename );
     784               0 :         return FALSE;
     785                 :     }
     786                 : 
     787                 : /* -------------------------------------------------------------------- */
     788                 : /*      We assume the user selects the .ers file.                       */
     789                 : /* -------------------------------------------------------------------- */
     790           12752 :     if( poOpenInfo->nHeaderBytes < 15
     791                 :         || !EQUALN((const char *) poOpenInfo->pabyHeader,"DatasetHeader ",14) )
     792           12702 :         return FALSE;
     793                 : 
     794              50 :     return TRUE;
     795                 : }
     796                 : 
     797                 : /************************************************************************/
     798                 : /*                                Open()                                */
     799                 : /************************************************************************/
     800                 : 
     801            2659 : GDALDataset *ERSDataset::Open( GDALOpenInfo * poOpenInfo )
     802                 : 
     803                 : {
     804            2659 :     if( !Identify( poOpenInfo ) )
     805            2609 :         return NULL;
     806                 : 
     807                 : /* -------------------------------------------------------------------- */
     808                 : /*      Open the .ers file, and read the first line.                    */
     809                 : /* -------------------------------------------------------------------- */
     810              50 :     VSILFILE *fpERS = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     811                 :     
     812              50 :     if( fpERS == NULL )
     813               0 :         return NULL;
     814                 : 
     815              50 :     CPLReadLineL( fpERS );
     816                 : 
     817                 : /* -------------------------------------------------------------------- */
     818                 : /*      Now ingest the rest of the file as a tree of header nodes.      */
     819                 : /* -------------------------------------------------------------------- */
     820              50 :     ERSHdrNode *poHeader = new ERSHdrNode();
     821                 : 
     822              50 :     if( !poHeader->ParseChildren( fpERS ) )
     823                 :     {
     824               0 :         delete poHeader;
     825               0 :         VSIFCloseL( fpERS );
     826               0 :         return NULL;
     827                 :     }
     828                 : 
     829              50 :     VSIFCloseL( fpERS );
     830                 : 
     831                 : /* -------------------------------------------------------------------- */
     832                 : /*      Do we have the minimum required information from this header?   */
     833                 : /* -------------------------------------------------------------------- */
     834              50 :     if( poHeader->Find( "RasterInfo.NrOfLines" ) == NULL 
     835                 :         || poHeader->Find( "RasterInfo.NrOfCellsPerLine" ) == NULL 
     836                 :         || poHeader->Find( "RasterInfo.NrOfBands" ) == NULL )
     837                 :     {
     838               0 :         if( poHeader->FindNode( "Algorithm" ) != NULL )
     839                 :         {
     840                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
     841                 :                       "%s appears to be an algorithm ERS file, which is not currently supported.", 
     842               0 :                       poOpenInfo->pszFilename );
     843                 :         }
     844               0 :         delete poHeader;
     845               0 :         return NULL;
     846                 :     }
     847                 : 
     848                 : /* -------------------------------------------------------------------- */
     849                 : /*      Create a corresponding GDALDataset.                             */
     850                 : /* -------------------------------------------------------------------- */
     851                 :     ERSDataset     *poDS;
     852                 : 
     853              50 :     poDS = new ERSDataset();
     854              50 :     poDS->poHeader = poHeader;
     855              50 :     poDS->eAccess = poOpenInfo->eAccess;
     856                 : 
     857                 : /* -------------------------------------------------------------------- */
     858                 : /*      Capture some information from the file that is of interest.     */
     859                 : /* -------------------------------------------------------------------- */
     860              50 :     int nBands = atoi(poHeader->Find( "RasterInfo.NrOfBands" ));
     861              50 :     poDS->nRasterXSize = atoi(poHeader->Find( "RasterInfo.NrOfCellsPerLine" ));
     862              50 :     poDS->nRasterYSize = atoi(poHeader->Find( "RasterInfo.NrOfLines" ));
     863                 :     
     864             100 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
     865                 :         !GDALCheckBandCount(nBands, FALSE))
     866                 :     {
     867               0 :         delete poDS;
     868               0 :         return NULL;
     869                 :     }
     870                 : 
     871                 : /* -------------------------------------------------------------------- */
     872                 : /*     Get the HeaderOffset if it exists in the header                  */
     873                 : /* -------------------------------------------------------------------- */
     874              50 :     GIntBig nHeaderOffset = 0;
     875              50 :     if( poHeader->Find( "HeaderOffset" ) != NULL )
     876                 :     {
     877               1 :         nHeaderOffset = atoi(poHeader->Find( "HeaderOffset" ));
     878                 :     }
     879                 : 
     880                 : /* -------------------------------------------------------------------- */
     881                 : /*      Establish the data type.                                        */
     882                 : /* -------------------------------------------------------------------- */
     883                 :     GDALDataType eType;
     884                 :     CPLString osCellType = poHeader->Find( "RasterInfo.CellType", 
     885              50 :                                            "Unsigned8BitInteger" );
     886              50 :     if( EQUAL(osCellType,"Unsigned8BitInteger") )
     887              22 :         eType = GDT_Byte;
     888              28 :     else if( EQUAL(osCellType,"Signed8BitInteger") )
     889               4 :         eType = GDT_Byte;
     890              24 :     else if( EQUAL(osCellType,"Unsigned16BitInteger") )
     891               3 :         eType = GDT_UInt16;
     892              21 :     else if( EQUAL(osCellType,"Signed16BitInteger") )
     893               4 :         eType = GDT_Int16;
     894              17 :     else if( EQUAL(osCellType,"Unsigned32BitInteger") )
     895               3 :         eType = GDT_UInt32;
     896              14 :     else if( EQUAL(osCellType,"Signed32BitInteger") )
     897               3 :         eType = GDT_Int32;
     898              11 :     else if( EQUAL(osCellType,"IEEE4ByteReal") )
     899               8 :         eType = GDT_Float32;
     900               3 :     else if( EQUAL(osCellType,"IEEE8ByteReal") )
     901               3 :         eType = GDT_Float64;
     902                 :     else
     903                 :     {
     904               0 :         CPLDebug( "ERS", "Unknown CellType '%s'", osCellType.c_str() );
     905               0 :         eType = GDT_Byte;
     906                 :     }
     907                 : 
     908                 : /* -------------------------------------------------------------------- */
     909                 : /*      Pick up the word order.                                         */
     910                 : /* -------------------------------------------------------------------- */
     911                 :     int bNative;
     912                 : 
     913                 : #ifdef CPL_LSB
     914                 :     bNative = EQUAL(poHeader->Find( "ByteOrder", "LSBFirst" ),
     915              50 :                     "LSBFirst");
     916                 : #else
     917                 :     bNative = EQUAL(poHeader->Find( "ByteOrder", "MSBFirst" ),
     918                 :                     "MSBFirst");
     919                 : #endif
     920                 : 
     921                 : /* -------------------------------------------------------------------- */
     922                 : /*      Figure out the name of the target file.                         */
     923                 : /* -------------------------------------------------------------------- */
     924              50 :     CPLString osPath = CPLGetPath( poOpenInfo->pszFilename );
     925              50 :     CPLString osDataFile = poHeader->Find( "DataFile", "" );
     926              50 :     CPLString osDataFilePath;
     927                 : 
     928              50 :     if( osDataFile.length() == 0 ) // just strip off extension.
     929                 :     {
     930              50 :         osDataFile = CPLGetFilename( poOpenInfo->pszFilename );
     931              50 :         osDataFile = osDataFile.substr( 0, osDataFile.find_last_of('.') );
     932                 :     }
     933                 :         
     934              50 :     osDataFilePath = CPLFormFilename( osPath, osDataFile, NULL );
     935                 : 
     936                 : /* -------------------------------------------------------------------- */
     937                 : /*      DataSetType = Translated files are links to things like ecw     */
     938                 : /*      files.                                                          */
     939                 : /* -------------------------------------------------------------------- */
     940              50 :     if( EQUAL(poHeader->Find("DataSetType",""),"Translated") )
     941                 :     {
     942                 :         poDS->poDepFile = (GDALDataset *) 
     943               0 :             GDALOpenShared( osDataFilePath, poOpenInfo->eAccess );
     944                 : 
     945               0 :         if( poDS->poDepFile != NULL 
     946                 :             && poDS->poDepFile->GetRasterCount() >= nBands )
     947                 :         {
     948                 :             int iBand;
     949                 : 
     950               0 :             for( iBand = 0; iBand < nBands; iBand++ )
     951                 :             {
     952                 :                 // Assume pixel interleaved.
     953                 :                 poDS->SetBand( iBand+1, 
     954               0 :                                poDS->poDepFile->GetRasterBand( iBand+1 ) );
     955                 :             }
     956                 :         }
     957                 :     }
     958                 : 
     959                 : /* ==================================================================== */
     960                 : /*      While ERStorage indicates a raw file.                           */
     961                 : /* ==================================================================== */
     962              50 :     else if( EQUAL(poHeader->Find("DataSetType",""),"ERStorage") )
     963                 :     {
     964                 :         // Open data file.
     965              50 :         if( poOpenInfo->eAccess == GA_Update )
     966              34 :             poDS->fpImage = VSIFOpenL( osDataFilePath, "r+" );
     967                 :         else
     968              16 :             poDS->fpImage = VSIFOpenL( osDataFilePath, "r" );
     969                 : 
     970              50 :         poDS->osRawFilename = osDataFilePath;
     971                 : 
     972              50 :         if( poDS->fpImage != NULL )
     973                 :         {
     974              50 :             int iWordSize = GDALGetDataTypeSize(eType) / 8;
     975                 :             int iBand;
     976                 : 
     977             140 :             for( iBand = 0; iBand < nBands; iBand++ )
     978                 :             {
     979                 :                 // Assume pixel interleaved.
     980                 :                 poDS->SetBand( 
     981                 :                     iBand+1, 
     982                 :                     new ERSRasterBand( poDS, iBand+1, poDS->fpImage,
     983                 :                                        nHeaderOffset 
     984                 :                                        + iWordSize * iBand * poDS->nRasterXSize,
     985                 :                                        iWordSize,
     986                 :                                        iWordSize * nBands * poDS->nRasterXSize,
     987              90 :                                        eType, bNative, TRUE ));
     988              90 :                 if( EQUAL(osCellType,"Signed8BitInteger") )
     989                 :                     poDS->GetRasterBand(iBand+1)->
     990                 :                         SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", 
     991              12 :                                          "IMAGE_STRUCTURE" );
     992                 :             }
     993                 :         }
     994                 :     }
     995                 : 
     996                 : /* -------------------------------------------------------------------- */
     997                 : /*      Otherwise we have an error!                                     */
     998                 : /* -------------------------------------------------------------------- */
     999              50 :     if( poDS->nBands == 0 )
    1000                 :     {
    1001               0 :         delete poDS;
    1002               0 :         return NULL;
    1003                 :     }
    1004                 : 
    1005                 : /* -------------------------------------------------------------------- */
    1006                 : /*      Look for band descriptions.                                     */
    1007                 : /* -------------------------------------------------------------------- */
    1008              50 :     int iChild, iBand = 0;
    1009              50 :     ERSHdrNode *poRI = poHeader->FindNode( "RasterInfo" );
    1010                 : 
    1011             287 :     for( iChild = 0; 
    1012                 :          poRI != NULL && iChild < poRI->nItemCount && iBand < poDS->nBands; 
    1013                 :          iChild++ )
    1014                 :     {
    1015             263 :         if( poRI->papoItemChild[iChild] != NULL
    1016              26 :             && EQUAL(poRI->papszItemName[iChild],"BandId") )
    1017                 :         {
    1018                 :             const char *pszValue = 
    1019               9 :                 poRI->papoItemChild[iChild]->Find( "Value", NULL );
    1020                 : 
    1021               9 :             iBand++;
    1022               9 :             if( pszValue )
    1023                 :             {
    1024               9 :                 CPLPushErrorHandler( CPLQuietErrorHandler );
    1025               9 :                 poDS->GetRasterBand( iBand )->SetDescription( pszValue );
    1026               9 :                 CPLPopErrorHandler();
    1027                 :             }
    1028                 : 
    1029               9 :             pszValue = poRI->papoItemChild[iChild]->Find( "Units", NULL );
    1030               9 :             if ( pszValue )
    1031                 :             {
    1032               2 :                 CPLPushErrorHandler( CPLQuietErrorHandler );
    1033               2 :                 poDS->GetRasterBand( iBand )->SetUnitType( pszValue );
    1034               2 :                 CPLPopErrorHandler();
    1035                 :             }
    1036                 :         }
    1037                 :     }
    1038                 : 
    1039                 : /* -------------------------------------------------------------------- */
    1040                 : /*      Look for projection.                                            */
    1041                 : /* -------------------------------------------------------------------- */
    1042              50 :     OGRSpatialReference oSRS;
    1043                 : 
    1044              50 :     poDS->osProj = poHeader->Find( "CoordinateSpace.Projection", "" );
    1045              50 :     poDS->osDatum = poHeader->Find( "CoordinateSpace.Datum", "" );
    1046              50 :     poDS->osUnits = poHeader->Find( "CoordinateSpace.Units", "" );
    1047                 : 
    1048                 :     oSRS.importFromERM( poDS->osProj.size() ? poDS->osProj.c_str() : "RAW",
    1049                 :                         poDS->osDatum.size() ? poDS->osDatum.c_str() : "WGS84",
    1050              50 :                         poDS->osUnits.size() ? poDS->osUnits.c_str() : "METERS" );
    1051                 : 
    1052              50 :     CPLFree( poDS->pszProjection );
    1053              50 :     oSRS.exportToWkt( &(poDS->pszProjection) );
    1054                 : 
    1055                 : /* -------------------------------------------------------------------- */
    1056                 : /*      Look for the geotransform.                                      */
    1057                 : /* -------------------------------------------------------------------- */
    1058              50 :     if( poHeader->Find( "RasterInfo.RegistrationCoord.Eastings", NULL ) )
    1059                 :     {
    1060               6 :         poDS->bGotTransform = TRUE;
    1061                 :         poDS->adfGeoTransform[0] = CPLAtof( 
    1062               6 :             poHeader->Find( "RasterInfo.RegistrationCoord.Eastings", "" ));
    1063                 :         poDS->adfGeoTransform[1] = CPLAtof( 
    1064               6 :             poHeader->Find( "RasterInfo.CellInfo.Xdimension", "1.0" ));
    1065               6 :         poDS->adfGeoTransform[2] = 0.0;
    1066                 :         poDS->adfGeoTransform[3] = CPLAtof( 
    1067               6 :             poHeader->Find( "RasterInfo.RegistrationCoord.Northings", "" ));
    1068               6 :         poDS->adfGeoTransform[4] = 0.0;
    1069                 :         poDS->adfGeoTransform[5] = -CPLAtof( 
    1070               6 :             poHeader->Find( "RasterInfo.CellInfo.Ydimension", "1.0" ));
    1071                 :     }
    1072              44 :     else if( poHeader->Find( "RasterInfo.RegistrationCoord.Latitude", NULL )
    1073                 :              && poHeader->Find( "RasterInfo.CellInfo.Xdimension", NULL ) )
    1074                 :     {
    1075               2 :         poDS->bGotTransform = TRUE;
    1076                 :         poDS->adfGeoTransform[0] = ERSDMS2Dec( 
    1077               2 :             poHeader->Find( "RasterInfo.RegistrationCoord.Longitude", "" ));
    1078                 :         poDS->adfGeoTransform[1] = CPLAtof( 
    1079               2 :             poHeader->Find( "RasterInfo.CellInfo.Xdimension", "" ));
    1080               2 :         poDS->adfGeoTransform[2] = 0.0;
    1081                 :         poDS->adfGeoTransform[3] = ERSDMS2Dec( 
    1082               2 :             poHeader->Find( "RasterInfo.RegistrationCoord.Latitude", "" ));
    1083               2 :         poDS->adfGeoTransform[4] = 0.0;
    1084                 :         poDS->adfGeoTransform[5] = -CPLAtof( 
    1085               2 :             poHeader->Find( "RasterInfo.CellInfo.Ydimension", "" ));
    1086                 :     }
    1087                 : 
    1088                 : /* -------------------------------------------------------------------- */
    1089                 : /*      Adjust if we have a registration cell.                          */
    1090                 : /* -------------------------------------------------------------------- */
    1091              50 :     int iCellX = atoi(poHeader->Find("RasterInfo.RegistrationCellX", "1"));
    1092              50 :     int iCellY = atoi(poHeader->Find("RasterInfo.RegistrationCellY", "1"));
    1093                 : 
    1094              50 :     if( poDS->bGotTransform )
    1095                 :     {
    1096                 :         poDS->adfGeoTransform[0] -=
    1097               8 :             (iCellX-1) * poDS->adfGeoTransform[1]
    1098              16 :             + (iCellY-1) * poDS->adfGeoTransform[2];
    1099                 :         poDS->adfGeoTransform[3] -= 
    1100               8 :             (iCellX-1) * poDS->adfGeoTransform[4]
    1101              16 :             + (iCellY-1) * poDS->adfGeoTransform[5];
    1102                 :     }
    1103                 : 
    1104                 : /* -------------------------------------------------------------------- */
    1105                 : /*      Check for null values.                                          */
    1106                 : /* -------------------------------------------------------------------- */
    1107              50 :     if( poHeader->Find( "RasterInfo.NullCellValue", NULL ) )
    1108                 :     {
    1109               5 :         poDS->bHasNoDataValue = TRUE;
    1110               5 :         poDS->dfNoDataValue = CPLAtofM(poHeader->Find( "RasterInfo.NullCellValue" ));
    1111                 : 
    1112               5 :         if (poDS->poDepFile != NULL)
    1113                 :         {
    1114               0 :             CPLPushErrorHandler( CPLQuietErrorHandler );
    1115                 : 
    1116               0 :             for( iBand = 1; iBand <= poDS->nBands; iBand++ )
    1117               0 :                 poDS->GetRasterBand(iBand)->SetNoDataValue(poDS->dfNoDataValue);
    1118                 : 
    1119               0 :             CPLPopErrorHandler();
    1120                 :         }
    1121                 :     }
    1122                 : 
    1123                 : /* -------------------------------------------------------------------- */
    1124                 : /*      Do we have an "All" region?                                     */
    1125                 : /* -------------------------------------------------------------------- */
    1126              50 :     ERSHdrNode *poAll = NULL;
    1127                 : 
    1128             289 :     for( iChild = 0; 
    1129                 :          poRI != NULL && iChild < poRI->nItemCount; 
    1130                 :          iChild++ )
    1131                 :     {
    1132             266 :         if( poRI->papoItemChild[iChild] != NULL
    1133              27 :             && EQUAL(poRI->papszItemName[iChild],"RegionInfo") )
    1134                 :         {
    1135               0 :             if( EQUAL(poRI->papoItemChild[iChild]->Find("RegionName",""), 
    1136                 :                       "All") )
    1137               0 :                 poAll = poRI->papoItemChild[iChild];
    1138                 :         }
    1139                 :     }
    1140                 : 
    1141                 : /* -------------------------------------------------------------------- */
    1142                 : /*      Do we have statistics?                                          */
    1143                 : /* -------------------------------------------------------------------- */
    1144              50 :     if( poAll && poAll->FindNode( "Stats" ) )
    1145                 :     {
    1146               0 :         CPLPushErrorHandler( CPLQuietErrorHandler );
    1147                 : 
    1148               0 :         for( iBand = 1; iBand <= poDS->nBands; iBand++ )
    1149                 :         {
    1150                 :             const char *pszValue = 
    1151               0 :                 poAll->FindElem( "Stats.MinimumValue", iBand-1 );
    1152                 : 
    1153               0 :             if( pszValue )
    1154                 :                 poDS->GetRasterBand(iBand)->SetMetadataItem(
    1155               0 :                     "STATISTICS_MINIMUM", pszValue );
    1156                 : 
    1157               0 :             pszValue = poAll->FindElem( "Stats.MaximumValue", iBand-1 );
    1158                 : 
    1159               0 :             if( pszValue )
    1160                 :                 poDS->GetRasterBand(iBand)->SetMetadataItem(
    1161               0 :                     "STATISTICS_MAXIMUM", pszValue );
    1162                 : 
    1163               0 :             pszValue = poAll->FindElem( "Stats.MeanValue", iBand-1 );
    1164                 : 
    1165               0 :             if( pszValue )
    1166                 :                 poDS->GetRasterBand(iBand)->SetMetadataItem(
    1167               0 :                     "STATISTICS_MEAN", pszValue );
    1168                 : 
    1169               0 :             pszValue = poAll->FindElem( "Stats.MedianValue", iBand-1 );
    1170                 : 
    1171               0 :             if( pszValue )
    1172                 :                 poDS->GetRasterBand(iBand)->SetMetadataItem(
    1173               0 :                     "STATISTICS_MEDIAN", pszValue );
    1174                 :         }
    1175                 :         
    1176               0 :         CPLPopErrorHandler();
    1177                 :         
    1178                 :     }
    1179                 : 
    1180                 : /* -------------------------------------------------------------------- */
    1181                 : /*      Do we have GCPs.                                                */
    1182                 : /* -------------------------------------------------------------------- */
    1183              50 :     if( poHeader->FindNode( "RasterInfo.WarpControl" ) )
    1184               2 :         poDS->ReadGCPs();
    1185                 : 
    1186                 : /* -------------------------------------------------------------------- */
    1187                 : /*      Initialize any PAM information.                                 */
    1188                 : /* -------------------------------------------------------------------- */
    1189              50 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1190              50 :     poDS->TryLoadXML();
    1191                 :     
    1192                 :     // if no SR in xml, try aux
    1193              50 :     const char* pszPrj = poDS->GDALPamDataset::GetProjectionRef();
    1194              50 :     if( !pszPrj || strlen(pszPrj) == 0 )
    1195                 :     {
    1196                 :         // try aux
    1197              50 :         GDALDataset* poAuxDS = GDALFindAssociatedAuxFile( poOpenInfo->pszFilename, GA_ReadOnly, poDS );
    1198              50 :         if( poAuxDS )
    1199                 :         {
    1200               0 :             pszPrj = poAuxDS->GetProjectionRef();
    1201               0 :             if( pszPrj && strlen(pszPrj) > 0 )
    1202                 :             {
    1203               0 :                 CPLFree( poDS->pszProjection );
    1204               0 :                 poDS->pszProjection = CPLStrdup(pszPrj);
    1205                 :             }
    1206                 : 
    1207               0 :             GDALClose( poAuxDS );
    1208                 :         }
    1209                 :     }
    1210                 : /* -------------------------------------------------------------------- */
    1211                 : /*      Check for overviews.                                            */
    1212                 : /* -------------------------------------------------------------------- */
    1213              50 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    1214                 : 
    1215              50 :     return( poDS );
    1216                 : }
    1217                 : 
    1218                 : /************************************************************************/
    1219                 : /*                               Create()                               */
    1220                 : /************************************************************************/
    1221                 : 
    1222              60 : GDALDataset *ERSDataset::Create( const char * pszFilename,
    1223                 :                                  int nXSize, int nYSize, int nBands,
    1224                 :                                  GDALDataType eType, char ** papszOptions )
    1225                 : 
    1226                 : {
    1227                 : /* -------------------------------------------------------------------- */
    1228                 : /*      Verify settings.                                                */
    1229                 : /* -------------------------------------------------------------------- */
    1230              60 :     if (nBands <= 0)
    1231                 :     {
    1232                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1233               1 :                   "ERS driver does not support %d bands.\n", nBands);
    1234               1 :         return NULL;
    1235                 :     }
    1236                 : 
    1237              59 :     if( eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_UInt16
    1238                 :         && eType != GDT_Int32 && eType != GDT_UInt32
    1239                 :         && eType != GDT_Float32 && eType != GDT_Float64 )
    1240                 :     {
    1241                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1242                 :                   "The ERS driver does not supporting creating files of types %s.", 
    1243              12 :                   GDALGetDataTypeName( eType ) );
    1244              12 :         return NULL;
    1245                 :     }
    1246                 : 
    1247                 : /* -------------------------------------------------------------------- */
    1248                 : /*      Work out the name we want to use for the .ers and binary        */
    1249                 : /*      data files.                                                     */
    1250                 : /* -------------------------------------------------------------------- */
    1251              47 :     CPLString osBinFile, osErsFile;
    1252                 : 
    1253              47 :     if( EQUAL(CPLGetExtension( pszFilename ), "ers") )
    1254                 :     {
    1255               6 :         osErsFile = pszFilename;
    1256               6 :         osBinFile = osErsFile.substr(0,osErsFile.length()-4);
    1257                 :     }
    1258                 :     else
    1259                 :     {
    1260              41 :         osBinFile = pszFilename;
    1261              41 :         osErsFile = osBinFile + ".ers";
    1262                 :     }
    1263                 : 
    1264                 : /* -------------------------------------------------------------------- */
    1265                 : /*      Work out some values we will write.                             */
    1266                 : /* -------------------------------------------------------------------- */
    1267              47 :     const char *pszCellType = "Unsigned8BitInteger";
    1268                 : 
    1269              47 :     if( eType == GDT_Byte )
    1270              22 :         pszCellType = "Unsigned8BitInteger";
    1271              25 :     else if( eType == GDT_Int16 )
    1272               4 :         pszCellType = "Signed16BitInteger";
    1273              21 :     else if( eType == GDT_UInt16 )
    1274               4 :         pszCellType = "Unsigned16BitInteger";
    1275              17 :     else if( eType == GDT_Int32 )
    1276               4 :         pszCellType = "Signed32BitInteger";
    1277              13 :     else if( eType == GDT_UInt32 )
    1278               4 :         pszCellType = "Unsigned32BitInteger";
    1279               9 :     else if( eType == GDT_Float32 )
    1280               5 :         pszCellType = "IEEE4ByteReal";
    1281               4 :     else if( eType == GDT_Float64 )
    1282               4 :         pszCellType = "IEEE8ByteReal";
    1283                 :     else
    1284                 :     {
    1285               0 :         CPLAssert( FALSE );
    1286                 :     }
    1287                 : 
    1288                 : /* -------------------------------------------------------------------- */
    1289                 : /*      Handling for signed eight bit data.                             */
    1290                 : /* -------------------------------------------------------------------- */
    1291              47 :     const char *pszPixelType = CSLFetchNameValue( papszOptions, "PIXELTYPE" );
    1292              47 :     if( pszPixelType 
    1293                 :         && EQUAL(pszPixelType,"SIGNEDBYTE") 
    1294                 :         && eType == GDT_Byte )
    1295               1 :         pszCellType = "Signed8BitInteger";
    1296                 : 
    1297                 : /* -------------------------------------------------------------------- */
    1298                 : /*      Write binary file.                                              */
    1299                 : /* -------------------------------------------------------------------- */
    1300                 :     GUIntBig nSize;
    1301              47 :     GByte byZero = 0;
    1302                 : 
    1303              47 :     VSILFILE *fpBin = VSIFOpenL( osBinFile, "w" );
    1304                 : 
    1305              47 :     if( fpBin == NULL )
    1306                 :     {
    1307                 :         CPLError( CE_Failure, CPLE_FileIO, 
    1308                 :                   "Failed to create %s:\n%s", 
    1309              13 :                   osBinFile.c_str(), VSIStrerror( errno ) );
    1310              13 :         return NULL;
    1311                 :     }
    1312                 : 
    1313                 :     nSize = nXSize * (GUIntBig) nYSize 
    1314              34 :         * nBands * (GDALGetDataTypeSize(eType) / 8);
    1315              34 :     if( VSIFSeekL( fpBin, nSize-1, SEEK_SET ) != 0
    1316                 :         || VSIFWriteL( &byZero, 1, 1, fpBin ) != 1 )
    1317                 :     {
    1318                 :         CPLError( CE_Failure, CPLE_FileIO, 
    1319                 :                   "Failed to write %s:\n%s", 
    1320               0 :                   osBinFile.c_str(), VSIStrerror( errno ) );
    1321               0 :         VSIFCloseL( fpBin );
    1322               0 :         return NULL;
    1323                 :     }
    1324              34 :     VSIFCloseL( fpBin );
    1325                 : 
    1326                 : 
    1327                 : /* -------------------------------------------------------------------- */
    1328                 : /*      Try writing header file.                                        */
    1329                 : /* -------------------------------------------------------------------- */
    1330              34 :     VSILFILE *fpERS = VSIFOpenL( osErsFile, "w" );
    1331                 :     
    1332              34 :     if( fpERS == NULL )
    1333                 :     {
    1334                 :         CPLError( CE_Failure, CPLE_FileIO, 
    1335                 :                   "Failed to create %s:\n%s", 
    1336               0 :                   osErsFile.c_str(), VSIStrerror( errno ) );
    1337               0 :         return NULL;
    1338                 :     }
    1339                 : 
    1340              34 :     VSIFPrintfL( fpERS, "DatasetHeader Begin\n" );
    1341              34 :     VSIFPrintfL( fpERS, "\tVersion\t\t = \"6.0\"\n" );
    1342              34 :     VSIFPrintfL( fpERS, "\tName\t\t= \"%s\"\n", CPLGetFilename(osErsFile) );
    1343                 : 
    1344                 : // Last updated requires timezone info which we don't necessarily get
    1345                 : // get from VSICTime() so perhaps it is better to omit this.
    1346                 : //    VSIFPrintfL( fpERS, "\tLastUpdated\t= %s", 
    1347                 : //                 VSICTime( VSITime( NULL ) ) );
    1348                 : 
    1349              34 :     VSIFPrintfL( fpERS, "\tDataSetType\t= ERStorage\n" );
    1350              34 :     VSIFPrintfL( fpERS, "\tDataType\t= Raster\n" );
    1351              34 :     VSIFPrintfL( fpERS, "\tByteOrder\t= LSBFirst\n" );
    1352              34 :     VSIFPrintfL( fpERS, "\tRasterInfo Begin\n" );
    1353              34 :     VSIFPrintfL( fpERS, "\t\tCellType\t= %s\n", pszCellType );
    1354              34 :     VSIFPrintfL( fpERS, "\t\tNrOfLines\t= %d\n", nYSize );
    1355              34 :     VSIFPrintfL( fpERS, "\t\tNrOfCellsPerLine\t= %d\n", nXSize );
    1356              34 :     VSIFPrintfL( fpERS, "\t\tNrOfBands\t= %d\n", nBands );
    1357              34 :     VSIFPrintfL( fpERS, "\tRasterInfo End\n" );
    1358              34 :     if( VSIFPrintfL( fpERS, "DatasetHeader End\n" ) < 17 )
    1359                 :     {
    1360                 :         CPLError( CE_Failure, CPLE_FileIO, 
    1361                 :                   "Failed to write %s:\n%s", 
    1362               0 :                   osErsFile.c_str(), VSIStrerror( errno ) );
    1363               0 :         return NULL;
    1364                 :     }
    1365                 : 
    1366              34 :     VSIFCloseL( fpERS );
    1367                 : 
    1368                 : /* -------------------------------------------------------------------- */
    1369                 : /*      Reopen.                                                         */
    1370                 : /* -------------------------------------------------------------------- */
    1371              34 :     GDALOpenInfo oOpenInfo( osErsFile, GA_Update );
    1372              34 :     ERSDataset* poDS = (ERSDataset*) Open( &oOpenInfo );
    1373              34 :     if (poDS == NULL)
    1374               0 :         return NULL;
    1375                 : 
    1376                 : /* -------------------------------------------------------------------- */
    1377                 : /*      Fetch DATUM, PROJ and UNITS creation option                     */
    1378                 : /* -------------------------------------------------------------------- */
    1379              34 :     const char *pszDatum = CSLFetchNameValue( papszOptions, "DATUM" );
    1380              34 :     if (pszDatum)
    1381               1 :         poDS->osDatum = pszDatum;
    1382              34 :     const char *pszProj = CSLFetchNameValue( papszOptions, "PROJ" );
    1383              34 :     if (pszProj)
    1384               1 :         poDS->osProj = pszProj;
    1385              34 :     const char *pszUnits = CSLFetchNameValue( papszOptions, "UNITS" );
    1386              34 :     if (pszUnits)
    1387               1 :         poDS->osUnits = pszUnits;
    1388                 : 
    1389              34 :     if (pszDatum || pszProj || pszUnits)
    1390                 :     {
    1391                 :         poDS->WriteProjectionInfo(pszProj ? pszProj : "RAW",
    1392                 :                                   pszDatum ? pszDatum : "RAW",
    1393               1 :                                   pszUnits ? pszUnits : "METERS");
    1394                 :     }
    1395                 :     
    1396              34 :     return poDS;
    1397                 : }
    1398                 : 
    1399                 : /************************************************************************/
    1400                 : /*                         GDALRegister_ERS()                           */
    1401                 : /************************************************************************/
    1402                 : 
    1403             582 : void GDALRegister_ERS()
    1404                 : 
    1405                 : {
    1406                 :     GDALDriver  *poDriver;
    1407                 : 
    1408             582 :     if( GDALGetDriverByName( "ERS" ) == NULL )
    1409                 :     {
    1410             561 :         poDriver = new GDALDriver();
    1411                 :         
    1412             561 :         poDriver->SetDescription( "ERS" );
    1413                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1414             561 :                                    "ERMapper .ers Labelled" );
    1415                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1416             561 :                                    "frmt_ers.html" );
    1417                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    1418             561 :                                    "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
    1419                 : 
    1420                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    1421                 : "<CreationOptionList>"
    1422                 : "   <Option name='PIXELTYPE' type='string' description='By setting this to SIGNEDBYTE, a new Byte file can be forced to be written as signed byte'/>"
    1423                 : "   <Option name='PROJ' type='string' description='ERS Projection Name'/>"
    1424                 : "   <Option name='DATUM' type='string' description='ERS Datum Name' />"
    1425                 : "   <Option name='UNITS' type='string-select' description='ERS Projection Units'>"
    1426                 : "       <Value>METERS</Value>"
    1427                 : "       <Value>FEET</Value>"
    1428                 : "   </Option>"
    1429             561 : "</CreationOptionList>" );
    1430                 : 
    1431             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1432                 : 
    1433             561 :         poDriver->pfnOpen = ERSDataset::Open;
    1434             561 :         poDriver->pfnIdentify = ERSDataset::Identify;
    1435             561 :         poDriver->pfnCreate = ERSDataset::Create;
    1436                 : 
    1437             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1438                 :     }
    1439             582 : }

Generated by: LCOV version 1.7