LCOV - code coverage report
Current view: directory - frmts/gsg - gsbgdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 478 303 63.4 %
Date: 2012-04-28 Functions: 23 16 69.6 %

       1                 : /******************************************************************************
       2                 :  * $Id: gsbgdataset.cpp 23060 2011-09-05 17:58:30Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL
       5                 :  * Purpose:  Implements the Golden Software Binary Grid Format.
       6                 :  * Author:   Kevin Locke, kwl7@cornell.edu
       7                 :  *       (Based largely on aaigriddataset.cpp by Frank Warmerdam)
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2006, Kevin Locke <kwl7@cornell.edu>
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "cpl_conv.h"
      32                 : 
      33                 : #include <float.h>
      34                 : #include <limits.h>
      35                 : #include <assert.h>
      36                 : 
      37                 : #include "gdal_pam.h"
      38                 : 
      39                 : #ifndef DBL_MAX
      40                 : # ifdef __DBL_MAX__
      41                 : #  define DBL_MAX __DBL_MAX__
      42                 : # else
      43                 : #  define DBL_MAX 1.7976931348623157E+308
      44                 : # endif /* __DBL_MAX__ */
      45                 : #endif /* DBL_MAX */
      46                 : 
      47                 : #ifndef FLT_MAX
      48                 : # ifdef __FLT_MAX__
      49                 : #  define FLT_MAX __FLT_MAX__
      50                 : # else
      51                 : #  define FLT_MAX 3.40282347E+38F
      52                 : # endif /* __FLT_MAX__ */
      53                 : #endif /* FLT_MAX */
      54                 : 
      55                 : #ifndef INT_MAX
      56                 : # define INT_MAX 2147483647
      57                 : #endif /* INT_MAX */
      58                 : 
      59                 : #ifndef SHRT_MAX
      60                 : # define SHRT_MAX 32767
      61                 : #endif /* SHRT_MAX */
      62                 : 
      63                 : CPL_CVSID("$Id: gsbgdataset.cpp 23060 2011-09-05 17:58:30Z rouault $");
      64                 : 
      65                 : CPL_C_START
      66                 : void  GDALRegister_GSBG(void);
      67                 : CPL_C_END
      68                 : 
      69                 : /************************************************************************/
      70                 : /* ==================================================================== */
      71                 : /*        GSBGDataset       */
      72                 : /* ==================================================================== */
      73                 : /************************************************************************/
      74                 : 
      75                 : class GSBGRasterBand;
      76                 : 
      77                 : class GSBGDataset : public GDALPamDataset
      78              84 : {
      79                 :     friend class GSBGRasterBand;
      80                 : 
      81                 :     static const float fNODATA_VALUE;
      82                 :     static const size_t nHEADER_SIZE;
      83                 : 
      84                 :     static CPLErr WriteHeader( VSILFILE *fp, GInt16 nXSize, GInt16 nYSize,
      85                 :              double dfMinX, double dfMaxX,
      86                 :              double dfMinY, double dfMaxY,
      87                 :              double dfMinZ, double dfMaxZ );
      88                 : 
      89                 :     VSILFILE  *fp;
      90                 : 
      91                 :   public:
      92                 :     ~GSBGDataset();
      93                 : 
      94                 :     static GDALDataset *Open( GDALOpenInfo * );
      95                 :     static GDALDataset *Create( const char * pszFilename,
      96                 :         int nXSize, int nYSize, int nBands,
      97                 :         GDALDataType eType,
      98                 :         char **papszParmList );
      99                 :     static GDALDataset *CreateCopy( const char *pszFilename,
     100                 :             GDALDataset *poSrcDS,
     101                 :             int bStrict, char **papszOptions,
     102                 :             GDALProgressFunc pfnProgress,
     103                 :             void *pProgressData );
     104                 :     static CPLErr Delete( const char *pszFilename );
     105                 : 
     106                 :     CPLErr GetGeoTransform( double *padfGeoTransform );
     107                 :     CPLErr SetGeoTransform( double *padfGeoTransform );
     108                 : };
     109                 : 
     110                 : /* NOTE:  This is not mentioned in the spec, but Surfer 8 uses this value */
     111                 : /* 0x7effffee (Little Endian: eeffff7e) */
     112                 : const float GSBGDataset::fNODATA_VALUE = 1.701410009187828e+38f;
     113                 : 
     114                 : const size_t GSBGDataset::nHEADER_SIZE = 56;
     115                 : 
     116                 : /************************************************************************/
     117                 : /* ==================================================================== */
     118                 : /*                            GSBGRasterBand                            */
     119                 : /* ==================================================================== */
     120                 : /************************************************************************/
     121                 : 
     122                 : class GSBGRasterBand : public GDALPamRasterBand
     123                 : {
     124                 :     friend class GSBGDataset;
     125                 : 
     126                 :     double dfMinX;
     127                 :     double dfMaxX;
     128                 :     double dfMinY;
     129                 :     double dfMaxY;
     130                 :     double dfMinZ;
     131                 :     double dfMaxZ;
     132                 : 
     133                 :     float *pafRowMinZ;
     134                 :     float *pafRowMaxZ;
     135                 :     int nMinZRow;
     136                 :     int nMaxZRow;
     137                 : 
     138                 :     CPLErr ScanForMinMaxZ();
     139                 : 
     140                 :   public:
     141                 : 
     142                 :         GSBGRasterBand( GSBGDataset *, int );
     143                 :     ~GSBGRasterBand();
     144                 :     
     145                 :     CPLErr IReadBlock( int, int, void * );
     146                 :     CPLErr IWriteBlock( int, int, void * );
     147                 : 
     148                 :     double GetNoDataValue( int *pbSuccess = NULL );
     149                 :     double GetMinimum( int *pbSuccess = NULL );
     150                 :     double GetMaximum( int *pbSuccess = NULL );
     151                 : };
     152                 : 
     153                 : /************************************************************************/
     154                 : /*                           GSBGRasterBand()                           */
     155                 : /************************************************************************/
     156                 : 
     157              84 : GSBGRasterBand::GSBGRasterBand( GSBGDataset *poDS, int nBand ) :
     158                 :     pafRowMinZ(NULL),
     159                 :     pafRowMaxZ(NULL),
     160                 :     nMinZRow(-1),
     161              84 :     nMaxZRow(-1)
     162                 : 
     163                 : {
     164              84 :     this->poDS = poDS;
     165              84 :     this->nBand = nBand;
     166                 :     
     167              84 :     eDataType = GDT_Float32;
     168                 : 
     169              84 :     nBlockXSize = poDS->GetRasterXSize();
     170              84 :     nBlockYSize = 1;
     171              84 : }
     172                 : 
     173                 : /************************************************************************/
     174                 : /*                           ~GSBGRasterBand()                          */
     175                 : /************************************************************************/
     176                 : 
     177              84 : GSBGRasterBand::~GSBGRasterBand( )
     178                 : 
     179                 : {
     180              84 :     if( pafRowMinZ != NULL )
     181               2 :   CPLFree( pafRowMinZ );
     182              84 :     if( pafRowMaxZ != NULL )
     183               2 :   CPLFree( pafRowMaxZ );
     184              84 : }
     185                 : 
     186                 : /************************************************************************/
     187                 : /*                          ScanForMinMaxZ()                            */
     188                 : /************************************************************************/
     189                 : 
     190               2 : CPLErr GSBGRasterBand::ScanForMinMaxZ()
     191                 : 
     192                 : {
     193               2 :     float *pafRowVals = (float *)VSIMalloc2( nRasterXSize, 4 );
     194                 : 
     195               2 :     if( pafRowVals == NULL )
     196                 :     {
     197                 :   CPLError( CE_Failure, CPLE_OutOfMemory,
     198               0 :       "Unable to allocate row buffer to scan grid file.\n" );
     199               0 :   return CE_Failure;
     200                 :     }
     201                 : 
     202               2 :     double dfNewMinZ = DBL_MAX;
     203               2 :     double dfNewMaxZ = -DBL_MAX;
     204               2 :     int nNewMinZRow = 0;
     205               2 :     int nNewMaxZRow = 0;
     206                 : 
     207                 :     /* Since we have to scan, lets calc. statistics too */
     208               2 :     double dfSum = 0.0;
     209               2 :     double dfSum2 = 0.0;
     210               2 :     unsigned long nValuesRead = 0;
     211              42 :     for( int iRow=0; iRow<nRasterYSize; iRow++ )
     212                 :     {
     213              40 :   CPLErr eErr = IReadBlock( 0, iRow, pafRowVals );
     214              40 :   if( eErr != CE_None )
     215                 :   {
     216               0 :       VSIFree( pafRowVals );
     217               0 :       return CE_Failure;
     218                 :   }
     219                 : 
     220              40 :   pafRowMinZ[iRow] = FLT_MAX;
     221              40 :   pafRowMaxZ[iRow] = -FLT_MAX;
     222             840 :   for( int iCol=0; iCol<nRasterXSize; iCol++ )
     223                 :   {
     224             800 :       if( pafRowVals[iCol] == GSBGDataset::fNODATA_VALUE )
     225             800 :     continue;
     226                 : 
     227               0 :       if( pafRowVals[iCol] < pafRowMinZ[iRow] )
     228               0 :     pafRowMinZ[iRow] = pafRowVals[iCol];
     229                 : 
     230               0 :       if( pafRowVals[iCol] > pafRowMinZ[iRow] )
     231               0 :     pafRowMaxZ[iRow] = pafRowVals[iCol];
     232                 : 
     233               0 :       dfSum += pafRowVals[iCol];
     234               0 :       dfSum2 += pafRowVals[iCol] * pafRowVals[iCol];
     235               0 :       nValuesRead++;
     236                 :   }
     237                 : 
     238              40 :   if( pafRowMinZ[iRow] < dfNewMinZ )
     239                 :   {
     240               2 :       dfNewMinZ = pafRowMinZ[iRow];
     241               2 :       nNewMinZRow = iRow;
     242                 :   }
     243                 : 
     244              40 :   if( pafRowMaxZ[iRow] > dfNewMaxZ )
     245                 :   {
     246               2 :       dfNewMaxZ = pafRowMaxZ[iRow];
     247               2 :       nNewMaxZRow = iRow;
     248                 :   }
     249                 :     }
     250                 : 
     251               2 :     VSIFree( pafRowVals );
     252                 : 
     253               2 :     if( nValuesRead == 0 )
     254                 :     {
     255               2 :   dfMinZ = 0.0;
     256               2 :   dfMaxZ = 0.0;
     257               2 :   nMinZRow = 0;
     258               2 :   nMaxZRow = 0;
     259               2 :   return CE_None;
     260                 :     }
     261                 : 
     262               0 :     dfMinZ = dfNewMinZ;
     263               0 :     dfMaxZ = dfNewMaxZ;
     264               0 :     nMinZRow = nNewMinZRow;
     265               0 :     nMaxZRow = nNewMaxZRow;
     266                 : 
     267               0 :     double dfMean = dfSum / nValuesRead;
     268               0 :     double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean));
     269               0 :     SetStatistics( dfMinZ, dfMaxZ, dfMean, dfStdDev );
     270                 : 
     271               0 :     return CE_None;
     272                 : }
     273                 : 
     274                 : /************************************************************************/
     275                 : /*                             IReadBlock()                             */
     276                 : /************************************************************************/
     277                 : 
     278             280 : CPLErr GSBGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     279                 :            void * pImage )
     280                 : 
     281                 : {
     282             280 :     if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
     283               0 :   return CE_Failure;
     284                 : 
     285             280 :     GSBGDataset *poGDS = dynamic_cast<GSBGDataset *>(poDS);
     286             280 :     if( VSIFSeekL( poGDS->fp,
     287                 :        GSBGDataset::nHEADER_SIZE +
     288                 :                         4 * nRasterXSize * (nRasterYSize - nBlockYOff - 1),
     289                 :        SEEK_SET ) != 0 )
     290                 :     {
     291                 :   CPLError( CE_Failure, CPLE_FileIO,
     292               0 :       "Unable to seek to beginning of grid row.\n" );
     293               0 :   return CE_Failure;
     294                 :     }
     295                 : 
     296             280 :     if( VSIFReadL( pImage, sizeof(float), nBlockXSize,
     297                 :        poGDS->fp ) != static_cast<unsigned>(nBlockXSize) )
     298                 :     {
     299                 :   CPLError( CE_Failure, CPLE_FileIO,
     300               0 :       "Unable to read block from grid file.\n" );
     301               0 :   return CE_Failure;
     302                 :     }
     303                 : 
     304                 :     float *pfImage;
     305             280 :     pfImage = (float *)pImage;
     306             280 :     for( int iPixel=0; iPixel<nBlockXSize; iPixel++ )
     307                 :   CPL_LSBPTR32( pfImage+iPixel );
     308                 : 
     309             280 :     return CE_None;
     310                 : }
     311                 : 
     312                 : /************************************************************************/
     313                 : /*                            IWriteBlock()                             */
     314                 : /************************************************************************/
     315                 : 
     316              40 : CPLErr GSBGRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     317                 :             void *pImage )
     318                 : 
     319                 : {
     320              40 :     if( eAccess == GA_ReadOnly )
     321                 :     {
     322                 :   CPLError( CE_Failure, CPLE_NoWriteAccess,
     323               0 :       "Unable to write block, dataset opened read only.\n" );
     324               0 :   return CE_Failure;
     325                 :     }
     326                 : 
     327              40 :     if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
     328               0 :   return CE_Failure;
     329                 : 
     330              40 :     GSBGDataset *poGDS = dynamic_cast<GSBGDataset *>(poDS);
     331              40 :     assert( poGDS != NULL );
     332                 : 
     333              40 :     if( pafRowMinZ == NULL || pafRowMaxZ == NULL
     334                 :   || nMinZRow < 0 || nMaxZRow < 0 )
     335                 :     {
     336               2 :   pafRowMinZ = (float *)VSIMalloc2( nRasterYSize,sizeof(float) );
     337               2 :   if( pafRowMinZ == NULL )
     338                 :   {
     339                 :       CPLError( CE_Failure, CPLE_OutOfMemory,
     340               0 :           "Unable to allocate space for row minimums array.\n" );
     341               0 :       return CE_Failure;
     342                 :   }
     343                 : 
     344               2 :   pafRowMaxZ = (float *)VSIMalloc2( nRasterYSize,sizeof(float) );
     345               2 :   if( pafRowMaxZ == NULL )
     346                 :   {
     347               0 :       VSIFree( pafRowMinZ );
     348               0 :       pafRowMinZ = NULL;
     349                 :       CPLError( CE_Failure, CPLE_OutOfMemory,
     350               0 :           "Unable to allocate space for row maximums array.\n" );
     351               0 :       return CE_Failure;
     352                 :   }
     353                 : 
     354               2 :   CPLErr eErr = ScanForMinMaxZ();
     355               2 :   if( eErr != CE_None )
     356               0 :       return eErr;
     357                 :     }
     358                 : 
     359              40 :     if( VSIFSeekL( poGDS->fp,
     360                 :        GSBGDataset::nHEADER_SIZE +
     361                 :                         4 * nRasterXSize * (nRasterYSize - nBlockYOff - 1),
     362                 :        SEEK_SET ) != 0 )
     363                 :     {
     364                 :   CPLError( CE_Failure, CPLE_FileIO,
     365               0 :       "Unable to seek to beginning of grid row.\n" );
     366               0 :   return CE_Failure;
     367                 :     }
     368                 : 
     369              40 :     float *pfImage = (float *)pImage;
     370              40 :     pafRowMinZ[nBlockYOff] = FLT_MAX;
     371              40 :     pafRowMaxZ[nBlockYOff] = -FLT_MAX;
     372             840 :     for( int iPixel=0; iPixel<nBlockXSize; iPixel++ )
     373                 :     {
     374             800 :   if( pfImage[iPixel] != GSBGDataset::fNODATA_VALUE )
     375                 :   {
     376             800 :       if( pfImage[iPixel] < pafRowMinZ[nBlockYOff] )
     377             156 :     pafRowMinZ[nBlockYOff] = pfImage[iPixel];
     378                 : 
     379             800 :       if( pfImage[iPixel] > pafRowMaxZ[nBlockYOff] )
     380              86 :     pafRowMaxZ[nBlockYOff] = pfImage[iPixel];
     381                 :   }
     382                 : 
     383                 :   CPL_LSBPTR32( pfImage+iPixel );
     384                 :     }
     385                 : 
     386              40 :     if( VSIFWriteL( pImage, sizeof(float), nBlockXSize,
     387                 :         poGDS->fp ) != static_cast<unsigned>(nBlockXSize) )
     388                 :     {
     389                 :   CPLError( CE_Failure, CPLE_FileIO,
     390               0 :       "Unable to write block to grid file.\n" );
     391               0 :   return CE_Failure;
     392                 :     }
     393                 : 
     394                 :     /* Update min/max Z values as appropriate */
     395              40 :     bool bHeaderNeedsUpdate = false;
     396              40 :     if( nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ )
     397                 :     {
     398               2 :   double dfNewMinZ = DBL_MAX;
     399              42 :   for( int iRow=0; iRow<nRasterYSize; iRow++ )
     400                 :   {
     401              40 :       if( pafRowMinZ[iRow] < dfNewMinZ )
     402                 :       {
     403               2 :     dfNewMinZ = pafRowMinZ[iRow];
     404               2 :     nMinZRow = iRow;
     405                 :       }
     406                 :   }
     407                 : 
     408               2 :   if( dfNewMinZ != dfMinZ )
     409                 :   {
     410               2 :       dfMinZ = dfNewMinZ;
     411               2 :       bHeaderNeedsUpdate = true;
     412                 :   }
     413                 :     }
     414                 : 
     415              40 :     if( nMaxZRow == nBlockYOff && pafRowMaxZ[nBlockYOff] < dfMaxZ )
     416                 :     {
     417               0 :   double dfNewMaxZ = -DBL_MAX;
     418               0 :   for( int iRow=0; iRow<nRasterYSize; iRow++ )
     419                 :   {
     420               0 :       if( pafRowMaxZ[iRow] > dfNewMaxZ )
     421                 :       {
     422               0 :     dfNewMaxZ = pafRowMaxZ[iRow];
     423               0 :     nMaxZRow = iRow;
     424                 :       }
     425                 :   }
     426                 : 
     427               0 :   if( dfNewMaxZ != dfMaxZ )
     428                 :   {
     429               0 :       dfMaxZ = dfNewMaxZ;
     430               0 :       bHeaderNeedsUpdate = true;
     431                 :   }
     432                 :     }
     433                 : 
     434              40 :     if( pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ )
     435                 :     {
     436              12 :   if( pafRowMinZ[nBlockYOff] < dfMinZ )
     437                 :   {
     438               6 :       dfMinZ = pafRowMinZ[nBlockYOff];
     439               6 :       nMinZRow = nBlockYOff;
     440                 :   }
     441                 : 
     442              12 :   if( pafRowMaxZ[nBlockYOff] > dfMaxZ )
     443                 :   {
     444               8 :       dfMaxZ = pafRowMaxZ[nBlockYOff];
     445               8 :       nMaxZRow = nBlockYOff;
     446                 :   }
     447                 : 
     448              12 :   bHeaderNeedsUpdate = true;
     449                 :     }
     450                 : 
     451              40 :     if( bHeaderNeedsUpdate && dfMaxZ > dfMinZ )
     452                 :     {
     453                 :   CPLErr eErr = poGDS->WriteHeader( poGDS->fp,
     454                 :             (GInt16) nRasterXSize, 
     455                 :                                           (GInt16) nRasterYSize,
     456                 :             dfMinX, dfMaxX,
     457                 :             dfMinY, dfMaxY,
     458              12 :             dfMinZ, dfMaxZ );
     459              12 :   return eErr;
     460                 :     }
     461                 : 
     462              28 :     return CE_None;
     463                 : }
     464                 : 
     465                 : /************************************************************************/
     466                 : /*                           GetNoDataValue()                           */
     467                 : /************************************************************************/
     468                 : 
     469              14 : double GSBGRasterBand::GetNoDataValue( int * pbSuccess )
     470                 : {
     471              14 :     if( pbSuccess )
     472              14 :         *pbSuccess = TRUE;
     473                 : 
     474              14 :     return GSBGDataset::fNODATA_VALUE;
     475                 : }
     476                 : 
     477                 : /************************************************************************/
     478                 : /*                             GetMinimum()                             */
     479                 : /************************************************************************/
     480                 : 
     481               0 : double GSBGRasterBand::GetMinimum( int *pbSuccess )
     482                 : {
     483               0 :     if( pbSuccess )
     484               0 :         *pbSuccess = TRUE;
     485                 : 
     486               0 :     return dfMinZ;
     487                 : }
     488                 : 
     489                 : /************************************************************************/
     490                 : /*                             GetMaximum()                             */
     491                 : /************************************************************************/
     492                 : 
     493               0 : double GSBGRasterBand::GetMaximum( int *pbSuccess )
     494                 : {
     495               0 :     if( pbSuccess )
     496               0 :         *pbSuccess = TRUE;
     497                 : 
     498               0 :     return dfMaxZ;
     499                 : }
     500                 : 
     501                 : /************************************************************************/
     502                 : /* ==================================================================== */
     503                 : /*        GSBGDataset       */
     504                 : /* ==================================================================== */
     505                 : /************************************************************************/
     506                 : 
     507              84 : GSBGDataset::~GSBGDataset()
     508                 : 
     509                 : {
     510              84 :     FlushCache();
     511              84 :     if( fp != NULL )
     512              84 :         VSIFCloseL( fp );
     513              84 : }
     514                 : 
     515                 : /************************************************************************/
     516                 : /*                                Open()                                */
     517                 : /************************************************************************/
     518                 : 
     519           23460 : GDALDataset *GSBGDataset::Open( GDALOpenInfo * poOpenInfo )
     520                 : 
     521                 : {
     522                 :     /* Check for signature */
     523           23460 :     if( poOpenInfo->nHeaderBytes < 4
     524                 :   || !EQUALN((const char *) poOpenInfo->pabyHeader,"DSBB",4) )
     525                 :     {
     526           23376 :         return NULL;
     527                 :     }
     528                 : 
     529                 : /* -------------------------------------------------------------------- */
     530                 : /*      Create a corresponding GDALDataset.                             */
     531                 : /* -------------------------------------------------------------------- */
     532              84 :     GSBGDataset *poDS = new GSBGDataset();
     533                 : 
     534                 : /* -------------------------------------------------------------------- */
     535                 : /*      Open file with large file API.                                  */
     536                 : /* -------------------------------------------------------------------- */
     537              84 :     poDS->eAccess = poOpenInfo->eAccess;
     538              84 :     if( poOpenInfo->eAccess == GA_ReadOnly )
     539              34 :       poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     540                 :     else
     541              50 :       poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
     542                 : 
     543              84 :     if( poDS->fp == NULL )
     544                 :     {
     545               0 :   delete poDS;
     546                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     547                 :                   "VSIFOpenL(%s) failed unexpectedly.", 
     548               0 :                   poOpenInfo->pszFilename );
     549               0 :         return NULL;
     550                 :     }
     551                 :  
     552                 : /* -------------------------------------------------------------------- */
     553                 : /*      Read the header.                                                */
     554                 : /* -------------------------------------------------------------------- */
     555              84 :     if( VSIFSeekL( poDS->fp, 4, SEEK_SET ) != 0 )
     556                 :     {
     557               0 :   delete poDS;
     558                 :   CPLError( CE_Failure, CPLE_FileIO,
     559               0 :       "Unable to seek to start of grid file header.\n" );
     560               0 :   return NULL;
     561                 :     }
     562                 : 
     563                 :     /* Parse number of X axis grid rows */
     564                 :     GInt16 nTemp;
     565              84 :     if( VSIFReadL( (void *)&nTemp, 2, 1, poDS->fp ) != 1 )
     566                 :     {
     567               0 :   delete poDS;
     568               0 :   CPLError( CE_Failure, CPLE_FileIO, "Unable to read raster X size.\n" );
     569               0 :   return NULL;
     570                 :     }
     571              84 :     poDS->nRasterXSize = CPL_LSBWORD16( nTemp );
     572                 : 
     573              84 :     if( VSIFReadL( (void *)&nTemp, 2, 1, poDS->fp ) != 1 )
     574                 :     {
     575               0 :   delete poDS;
     576               0 :   CPLError( CE_Failure, CPLE_FileIO, "Unable to read raster Y size.\n" );
     577               0 :   return NULL;
     578                 :     }
     579              84 :     poDS->nRasterYSize = CPL_LSBWORD16( nTemp );
     580                 : 
     581              84 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     582                 :     {
     583               0 :         delete poDS;
     584               0 :         return NULL;
     585                 :     }
     586                 : 
     587                 : /* -------------------------------------------------------------------- */
     588                 : /*      Create band information objects.                                */
     589                 : /* -------------------------------------------------------------------- */
     590              84 :     GSBGRasterBand *poBand = new GSBGRasterBand( poDS, 1 );
     591                 : 
     592                 :     double dfTemp;
     593              84 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     594                 :     {
     595               0 :   delete poDS;
     596                 :   CPLError( CE_Failure, CPLE_FileIO,
     597               0 :       "Unable to read minimum X value.\n" );
     598               0 :   return NULL;
     599                 :     }
     600                 :     CPL_LSBPTR64( &dfTemp );
     601              84 :     poBand->dfMinX = dfTemp;
     602                 : 
     603              84 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     604                 :     {
     605               0 :   delete poDS;
     606                 :   CPLError( CE_Failure, CPLE_FileIO,
     607               0 :       "Unable to read maximum X value.\n" );
     608               0 :   return NULL;
     609                 :     }
     610                 :     CPL_LSBPTR64( &dfTemp );
     611              84 :     poBand->dfMaxX = dfTemp;
     612                 : 
     613              84 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     614                 :     {
     615               0 :   delete poDS;
     616                 :   CPLError( CE_Failure, CPLE_FileIO,
     617               0 :       "Unable to read minimum Y value.\n" );
     618               0 :   return NULL;
     619                 :     }
     620                 :     CPL_LSBPTR64( &dfTemp );
     621              84 :     poBand->dfMinY = dfTemp;
     622                 : 
     623              84 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     624                 :     {
     625               0 :   delete poDS;
     626                 :   CPLError( CE_Failure, CPLE_FileIO,
     627               0 :       "Unable to read maximum Y value.\n" );
     628               0 :   return NULL;
     629                 :     }
     630                 :     CPL_LSBPTR64( &dfTemp );
     631              84 :     poBand->dfMaxY = dfTemp;
     632                 : 
     633              84 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     634                 :     {
     635               0 :   delete poDS;
     636                 :   CPLError( CE_Failure, CPLE_FileIO,
     637               0 :       "Unable to read minimum Z value.\n" );
     638               0 :   return NULL;
     639                 :     }
     640                 :     CPL_LSBPTR64( &dfTemp );
     641              84 :     poBand->dfMinZ = dfTemp;
     642                 : 
     643              84 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     644                 :     {
     645               0 :   delete poDS;
     646                 :   CPLError( CE_Failure, CPLE_FileIO,
     647               0 :       "Unable to read maximum Z value.\n" );
     648               0 :   return NULL;
     649                 :     }
     650                 :     CPL_LSBPTR64( &dfTemp );
     651              84 :     poBand->dfMaxZ = dfTemp;
     652                 : 
     653              84 :     poDS->SetBand( 1, poBand );
     654                 : 
     655                 : /* -------------------------------------------------------------------- */
     656                 : /*      Initialize any PAM information.                                 */
     657                 : /* -------------------------------------------------------------------- */
     658              84 :     poDS->SetDescription( poOpenInfo->pszFilename );
     659              84 :     poDS->TryLoadXML();
     660                 : 
     661                 : /* -------------------------------------------------------------------- */
     662                 : /*      Check for external overviews.                                   */
     663                 : /* -------------------------------------------------------------------- */
     664              84 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
     665                 : 
     666              84 :     return poDS;
     667                 : }
     668                 : 
     669                 : /************************************************************************/
     670                 : /*                          GetGeoTransform()                           */
     671                 : /************************************************************************/
     672                 : 
     673              32 : CPLErr GSBGDataset::GetGeoTransform( double *padfGeoTransform )
     674                 : {
     675              32 :     if( padfGeoTransform == NULL )
     676               0 :   return CE_Failure;
     677                 : 
     678              32 :     GSBGRasterBand *poGRB = dynamic_cast<GSBGRasterBand *>(GetRasterBand( 1 ));
     679                 : 
     680              32 :     if( poGRB == NULL )
     681                 :     {
     682               0 :   padfGeoTransform[0] = 0;
     683               0 :   padfGeoTransform[1] = 1;
     684               0 :   padfGeoTransform[2] = 0;
     685               0 :   padfGeoTransform[3] = 0;
     686               0 :   padfGeoTransform[4] = 0;
     687               0 :   padfGeoTransform[5] = 1;
     688               0 :   return CE_Failure;
     689                 :     }
     690                 : 
     691                 :     /* check if we have a PAM GeoTransform stored */
     692              32 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     693              32 :     CPLErr eErr = GDALPamDataset::GetGeoTransform( padfGeoTransform );
     694              32 :     CPLPopErrorHandler();
     695                 : 
     696              32 :     if( eErr == CE_None )
     697               0 :   return CE_None;
     698                 : 
     699                 :     /* calculate pixel size first */
     700              32 :     padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX)/(nRasterXSize - 1);
     701              32 :     padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY)/(nRasterYSize - 1);
     702                 : 
     703                 :     /* then calculate image origin */
     704              32 :     padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2;
     705              32 :     padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2;
     706                 : 
     707                 :     /* tilt/rotation does not supported by the GS grids */
     708              32 :     padfGeoTransform[4] = 0.0;
     709              32 :     padfGeoTransform[2] = 0.0;
     710                 : 
     711              32 :     return CE_None;
     712                 : }
     713                 : 
     714                 : /************************************************************************/
     715                 : /*                          SetGeoTransform()                           */
     716                 : /************************************************************************/
     717                 : 
     718              24 : CPLErr GSBGDataset::SetGeoTransform( double *padfGeoTransform )
     719                 : {
     720              24 :     if( eAccess == GA_ReadOnly )
     721                 :     {
     722                 :   CPLError( CE_Failure, CPLE_NoWriteAccess,
     723               0 :       "Unable to set GeoTransform, dataset opened read only.\n" );
     724               0 :   return CE_Failure;
     725                 :     }
     726                 : 
     727              24 :     GSBGRasterBand *poGRB = dynamic_cast<GSBGRasterBand *>(GetRasterBand( 1 ));
     728                 : 
     729              24 :     if( poGRB == NULL || padfGeoTransform == NULL)
     730               0 :   return CE_Failure;
     731                 : 
     732                 :     /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
     733              24 :     CPLErr eErr = CE_None;
     734                 :     /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0
     735                 :   || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 )
     736                 :   eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform );
     737                 : 
     738                 :     if( eErr != CE_None )
     739                 :   return eErr;*/
     740                 : 
     741              24 :     double dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2;
     742                 :     double dfMaxX =
     743              24 :         padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0];
     744                 :     double dfMinY =
     745              24 :         padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3];
     746              24 :     double dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2;
     747                 : 
     748                 :     eErr = WriteHeader( fp, 
     749                 :                         (GInt16) poGRB->nRasterXSize, 
     750                 :                         (GInt16) poGRB->nRasterYSize,
     751                 :       dfMinX, dfMaxX, dfMinY, dfMaxY,
     752              24 :       poGRB->dfMinZ, poGRB->dfMaxZ );
     753                 : 
     754              24 :     if( eErr == CE_None )
     755                 :     {
     756              24 :   poGRB->dfMinX = dfMinX;
     757              24 :   poGRB->dfMaxX = dfMaxX;
     758              24 :   poGRB->dfMinY = dfMinY;
     759              24 :   poGRB->dfMaxY = dfMaxY;
     760                 :     }
     761                 : 
     762              24 :     return eErr;
     763                 : }
     764                 : 
     765                 : /************************************************************************/
     766                 : /*                             WriteHeader()                            */
     767                 : /************************************************************************/
     768                 : 
     769             110 : CPLErr GSBGDataset::WriteHeader( VSILFILE *fp, GInt16 nXSize, GInt16 nYSize,
     770                 :          double dfMinX, double dfMaxX,
     771                 :          double dfMinY, double dfMaxY,
     772                 :          double dfMinZ, double dfMaxZ )
     773                 : 
     774                 : {
     775             110 :     if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
     776                 :     {
     777                 :   CPLError( CE_Failure, CPLE_FileIO,
     778               0 :       "Unable to seek to start of grid file.\n" );
     779               0 :   return CE_Failure;
     780                 :     }
     781                 : 
     782             110 :     if( VSIFWriteL( (void *)"DSBB", 1, 4, fp ) != 4 )
     783                 :     {
     784                 :   CPLError( CE_Failure, CPLE_FileIO,
     785               0 :       "Unable to write signature to grid file.\n" );
     786               0 :   return CE_Failure;
     787                 :     }
     788                 : 
     789             110 :     GInt16 nTemp = CPL_LSBWORD16(nXSize);
     790             110 :     if( VSIFWriteL( (void *)&nTemp, 2, 1, fp ) != 1 )
     791                 :     {
     792                 :   CPLError( CE_Failure, CPLE_FileIO,
     793               0 :       "Unable to write raster X size to grid file.\n" );
     794               0 :   return CE_Failure;
     795                 :     }
     796                 : 
     797             110 :     nTemp = CPL_LSBWORD16(nYSize);
     798             110 :     if( VSIFWriteL( (void *)&nTemp, 2, 1, fp ) != 1 )
     799                 :     {
     800                 :   CPLError( CE_Failure, CPLE_FileIO,
     801               0 :       "Unable to write raster Y size to grid file.\n" );
     802               0 :   return CE_Failure;
     803                 :     }
     804                 : 
     805             110 :     double dfTemp = dfMinX;
     806                 :     CPL_LSBPTR64( &dfTemp );
     807             110 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     808                 :     {
     809                 :   CPLError( CE_Failure, CPLE_FileIO,
     810               0 :       "Unable to write minimum X value to grid file.\n" );
     811               0 :   return CE_Failure;
     812                 :     }
     813                 : 
     814             110 :     dfTemp = dfMaxX;
     815                 :     CPL_LSBPTR64( &dfTemp );
     816             110 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     817                 :     {
     818                 :   CPLError( CE_Failure, CPLE_FileIO,
     819               0 :       "Unable to write maximum X value to grid file.\n" );
     820               0 :   return CE_Failure;
     821                 :     }
     822                 : 
     823             110 :     dfTemp = dfMinY;
     824                 :     CPL_LSBPTR64( &dfTemp );
     825             110 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     826                 :     {
     827                 :   CPLError( CE_Failure, CPLE_FileIO,
     828               0 :       "Unable to write minimum Y value to grid file.\n" );
     829               0 :   return CE_Failure;
     830                 :     }
     831                 : 
     832             110 :     dfTemp = dfMaxY;
     833                 :     CPL_LSBPTR64( &dfTemp );
     834             110 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     835                 :     {
     836                 :   CPLError( CE_Failure, CPLE_FileIO,
     837               0 :       "Unable to write maximum Y value to grid file.\n" );
     838               0 :   return CE_Failure;
     839                 :     }
     840                 : 
     841             110 :     dfTemp = dfMinZ;
     842                 :     CPL_LSBPTR64( &dfTemp );
     843             110 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     844                 :     {
     845                 :   CPLError( CE_Failure, CPLE_FileIO,
     846               0 :       "Unable to write minimum Z value to grid file.\n" );
     847               0 :   return CE_Failure;
     848                 :     }
     849                 : 
     850             110 :     dfTemp = dfMaxZ;
     851                 :     CPL_LSBPTR64( &dfTemp );
     852             110 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     853                 :     {
     854                 :   CPLError( CE_Failure, CPLE_FileIO,
     855               0 :       "Unable to write maximum Z value to grid file.\n" );
     856               0 :   return CE_Failure;
     857                 :     }
     858                 : 
     859             110 :     return CE_None;
     860                 : }
     861                 : 
     862                 : /************************************************************************/
     863                 : /*                               Create()                               */
     864                 : /************************************************************************/
     865                 : 
     866              54 : GDALDataset *GSBGDataset::Create( const char * pszFilename,
     867                 :           int nXSize, int nYSize, int nBands,
     868                 :           GDALDataType eType,
     869                 :           char **papszParmList )
     870                 : 
     871                 : {
     872              54 :     if( nXSize <= 0 || nYSize <= 0 )
     873                 :     {
     874                 :   CPLError( CE_Failure, CPLE_IllegalArg,
     875                 :       "Unable to create grid, both X and Y size must be "
     876               0 :       "non-negative.\n" );
     877                 : 
     878               0 :   return NULL;
     879                 :     }
     880              54 :     else if( nXSize > SHRT_MAX
     881                 :        || nYSize > SHRT_MAX )
     882                 :     {
     883                 :   CPLError( CE_Failure, CPLE_IllegalArg,
     884                 :       "Unable to create grid, Golden Software Binary Grid format "
     885                 :       "only supports sizes up to %dx%d.  %dx%d not supported.\n",
     886               0 :       SHRT_MAX, SHRT_MAX, nXSize, nYSize );
     887                 : 
     888               0 :   return NULL;
     889                 :     }
     890                 : 
     891              54 :     if( eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16
     892                 :         && eType != GDT_Int16 )
     893                 :     {
     894                 :         CPLError( CE_Failure, CPLE_AppDefined,
     895                 :       "Golden Software ASCII Grid only supports Byte, Int16, "
     896                 :       "Uint16, and Float32 datatypes.  Unable to create with "
     897              28 :       "type %s.\n", GDALGetDataTypeName( eType ) );
     898                 : 
     899              28 :         return NULL;
     900                 :     }
     901                 : 
     902              26 :     VSILFILE *fp = VSIFOpenL( pszFilename, "w+b" );
     903                 : 
     904              26 :     if( fp == NULL )
     905                 :     {
     906                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     907                 :                   "Attempt to create file '%s' failed.\n",
     908               0 :                   pszFilename );
     909               0 :         return NULL;
     910                 :     }
     911                 :     
     912                 :     CPLErr eErr = WriteHeader( fp, (GInt16) nXSize, (GInt16) nYSize,
     913              26 :              0.0, nXSize, 0.0, nYSize, 0.0, 0.0 );
     914              26 :     if( eErr != CE_None )
     915                 :     {
     916               0 :   VSIFCloseL( fp );
     917               0 :   return NULL;
     918                 :     }
     919                 : 
     920              26 :     float fVal = fNODATA_VALUE;
     921                 :     CPL_LSBPTR32( &fVal );
     922            2466 :     for( int iRow = 0; iRow < nYSize; iRow++ )
     923                 :     {
     924          243240 :   for( int iCol=0; iCol<nXSize; iCol++ )
     925                 :   {
     926          240800 :       if( VSIFWriteL( (void *)&fVal, 4, 1, fp ) != 1 )
     927                 :       {
     928               0 :     VSIFCloseL( fp );
     929                 :     CPLError( CE_Failure, CPLE_FileIO,
     930               0 :         "Unable to write grid cell.  Disk full?\n" );
     931               0 :     return NULL;
     932                 :       }
     933                 :   }
     934                 :     }
     935                 : 
     936              26 :     VSIFCloseL( fp );
     937                 : 
     938              26 :     return (GDALDataset *)GDALOpen( pszFilename, GA_Update );
     939                 : }
     940                 : 
     941                 : /************************************************************************/
     942                 : /*                             CreateCopy()                             */
     943                 : /************************************************************************/
     944                 : 
     945              38 : GDALDataset *GSBGDataset::CreateCopy( const char *pszFilename,
     946                 :               GDALDataset *poSrcDS,
     947                 :               int bStrict, char **papszOptions,
     948                 :               GDALProgressFunc pfnProgress,
     949                 :               void *pProgressData )
     950                 : {
     951              38 :     if( pfnProgress == NULL )
     952               0 :   pfnProgress = GDALDummyProgress;
     953                 : 
     954              38 :     int nBands = poSrcDS->GetRasterCount();
     955              38 :     if (nBands == 0)
     956                 :     {
     957                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     958               2 :                   "GSBG driver does not support source dataset with zero band.\n");
     959               2 :         return NULL;
     960                 :     }
     961              36 :     else if (nBands > 1)
     962                 :     {
     963               8 :   if( bStrict )
     964                 :   {
     965                 :       CPLError( CE_Failure, CPLE_NotSupported,
     966                 :           "Unable to create copy, Golden Software Binary Grid "
     967               8 :           "format only supports one raster band.\n" );
     968               8 :       return NULL;
     969                 :   }
     970                 :   else
     971                 :       CPLError( CE_Warning, CPLE_NotSupported,
     972                 :           "Golden Software Binary Grid format only supports one "
     973               0 :           "raster band, first band will be copied.\n" );
     974                 :     }
     975                 : 
     976              28 :     GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( 1 );
     977              28 :     if( poSrcBand->GetXSize() > SHRT_MAX
     978                 :   || poSrcBand->GetYSize() > SHRT_MAX )
     979                 :     {
     980                 :   CPLError( CE_Failure, CPLE_IllegalArg,
     981                 :       "Unable to create grid, Golden Software Binary Grid format "
     982                 :       "only supports sizes up to %dx%d.  %dx%d not supported.\n",
     983                 :       SHRT_MAX, SHRT_MAX,
     984               0 :       poSrcBand->GetXSize(), poSrcBand->GetYSize() );
     985                 : 
     986               0 :   return NULL;
     987                 :     }
     988                 : 
     989              28 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
     990                 :     {
     991               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated\n" );
     992               0 :         return NULL;
     993                 :     }
     994                 : 
     995              28 :     VSILFILE    *fp = VSIFOpenL( pszFilename, "w+b" );
     996                 : 
     997              28 :     if( fp == NULL )
     998                 :     {
     999                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    1000                 :                   "Attempt to create file '%s' failed.\n",
    1001               4 :                   pszFilename );
    1002               4 :         return NULL;
    1003                 :     }
    1004                 : 
    1005              24 :     GInt16  nXSize = (GInt16) poSrcBand->GetXSize();
    1006              24 :     GInt16  nYSize = (GInt16) poSrcBand->GetYSize();
    1007                 :     double  adfGeoTransform[6];
    1008                 : 
    1009              24 :     poSrcDS->GetGeoTransform( adfGeoTransform );
    1010                 : 
    1011              24 :     double dfMinX = adfGeoTransform[0] + adfGeoTransform[1] / 2;
    1012              24 :     double dfMaxX = adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0];
    1013              24 :     double dfMinY = adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3];
    1014              24 :     double dfMaxY = adfGeoTransform[3] + adfGeoTransform[5] / 2;
    1015                 :     CPLErr eErr = WriteHeader( fp, nXSize, nYSize,
    1016              24 :              dfMinX, dfMaxX, dfMinY, dfMaxY, 0.0, 0.0 );
    1017                 : 
    1018              24 :     if( eErr != CE_None )
    1019                 :     {
    1020               0 :   VSIFCloseL( fp );
    1021               0 :         return NULL;
    1022                 :     }
    1023                 : 
    1024                 : /* -------------------------------------------------------------------- */
    1025                 : /*      Copy band data.             */
    1026                 : /* -------------------------------------------------------------------- */
    1027              24 :     float *pfData = (float *)VSIMalloc2( nXSize, sizeof( float ) );
    1028              24 :     if( pfData == NULL )
    1029                 :     {
    1030               0 :   VSIFCloseL( fp );
    1031                 :   CPLError( CE_Failure, CPLE_OutOfMemory,
    1032               0 :       "Unable to create copy, unable to allocate line buffer.\n" );
    1033               0 :   return NULL;
    1034                 :     }
    1035                 : 
    1036                 :     int     bSrcHasNDValue;
    1037              24 :     float   fSrcNoDataValue = (float) poSrcBand->GetNoDataValue( &bSrcHasNDValue );
    1038              24 :     double  dfMinZ = DBL_MAX;
    1039              24 :     double  dfMaxZ = -DBL_MAX;
    1040             284 :     for( GInt16 iRow = nYSize - 1; iRow >= 0; iRow-- )
    1041                 :     {
    1042                 :   eErr = poSrcBand->RasterIO( GF_Read, 0, iRow,
    1043                 :             nXSize, 1, pfData,
    1044             260 :             nXSize, 1, GDT_Float32, 0, 0 );
    1045                 : 
    1046             260 :   if( eErr != CE_None )
    1047                 :   {
    1048               0 :       VSIFCloseL( fp );
    1049               0 :       VSIFree( pfData );
    1050               0 :       return NULL;
    1051                 :   }
    1052                 : 
    1053            3260 :   for( int iCol=0; iCol<nXSize; iCol++ )
    1054                 :   {
    1055            3000 :       if( bSrcHasNDValue && pfData[iCol] == fSrcNoDataValue )
    1056                 :       {
    1057               0 :     pfData[iCol] = fNODATA_VALUE;
    1058                 :       }
    1059                 :       else
    1060                 :       {
    1061            3000 :     if( pfData[iCol] > dfMaxZ )
    1062              28 :         dfMaxZ = pfData[iCol];
    1063                 : 
    1064            3000 :     if( pfData[iCol] < dfMinZ )
    1065              38 :         dfMinZ = pfData[iCol];
    1066                 :       }
    1067                 : 
    1068                 :       CPL_LSBPTR32( pfData+iCol );
    1069                 :   }
    1070                 : 
    1071             260 :   if( VSIFWriteL( (void *)pfData, 4, nXSize,
    1072                 :       fp ) != static_cast<unsigned>(nXSize) )
    1073                 :   {
    1074               0 :       VSIFCloseL( fp );
    1075               0 :       VSIFree( pfData );
    1076                 :       CPLError( CE_Failure, CPLE_FileIO,
    1077               0 :           "Unable to write grid row. Disk full?\n" );
    1078               0 :       return NULL;
    1079                 :   }
    1080                 : 
    1081             260 :   if( !pfnProgress( static_cast<double>(iRow)/nYSize,
    1082                 :         NULL, pProgressData ) )
    1083                 :   {
    1084               0 :       VSIFCloseL( fp );
    1085               0 :       VSIFree( pfData );
    1086               0 :       CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1087               0 :       return NULL;
    1088                 :   }
    1089                 :     }
    1090                 : 
    1091              24 :     VSIFree( pfData );
    1092                 : 
    1093                 :     /* write out the min and max values */
    1094                 :     eErr = WriteHeader( fp, nXSize, nYSize,
    1095              24 :       dfMinX, dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ );
    1096                 : 
    1097              24 :     if( eErr != CE_None )
    1098                 :     {
    1099               0 :   VSIFCloseL( fp );
    1100               0 :         return NULL;
    1101                 :     }
    1102                 : 
    1103              24 :     VSIFCloseL( fp );
    1104                 : 
    1105                 :     GDALPamDataset *poDstDS = (GDALPamDataset *)GDALOpen( pszFilename,
    1106              24 :                 GA_Update );
    1107              24 :     if( poDstDS == NULL )
    1108                 :     {
    1109               0 :   VSIUnlink( pszFilename );
    1110                 :   CPLError( CE_Failure, CPLE_FileIO,
    1111               0 :       "Unable to open copy of dataset.\n" );
    1112               0 :   return NULL;
    1113                 :     }
    1114              24 :     else if( dynamic_cast<GSBGDataset *>(poDstDS) == NULL )
    1115                 :     {
    1116               0 :   VSIUnlink( pszFilename );
    1117               0 :   delete poDstDS;
    1118                 :   CPLError( CE_Failure, CPLE_FileIO,
    1119               0 :       "Copy dataset not opened as Golden Surfer Binary Grid!?\n" );
    1120               0 :   return NULL;
    1121                 :     }
    1122                 : 
    1123              24 :     GDALRasterBand *poDstBand = poSrcDS->GetRasterBand(1);
    1124              24 :     if( poDstBand == NULL )
    1125                 :     {
    1126               0 :   VSIUnlink( pszFilename );
    1127               0 :   delete poDstDS;
    1128                 :   CPLError( CE_Failure, CPLE_FileIO,
    1129               0 :       "Unable to open copy of raster band?\n" );
    1130               0 :   return NULL;
    1131                 :     }
    1132                 : 
    1133                 : /* -------------------------------------------------------------------- */
    1134                 : /*      Attempt to copy metadata.         */
    1135                 : /* -------------------------------------------------------------------- */
    1136              24 :     if( !bStrict )
    1137               2 :   CPLPushErrorHandler( CPLQuietErrorHandler );
    1138                 : 
    1139                 :     /* non-zero transform 2 or 4 or negative 1 or 5  not supported natively */
    1140                 :     /*if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0
    1141                 :   || adfGeoTransform[1] < 0.0 || adfGeoTransform[5] < 0.0 )
    1142                 :   poDstDS->GDALPamDataset::SetGeoTransform( adfGeoTransform );*/
    1143                 : 
    1144              24 :     const char *szProjectionRef = poSrcDS->GetProjectionRef();
    1145              24 :     if( *szProjectionRef != '\0' )
    1146              22 :   poDstDS->SetProjection( szProjectionRef );
    1147                 : 
    1148              24 :     char **pszMetadata = poSrcDS->GetMetadata();
    1149              24 :     if( pszMetadata != NULL )
    1150              22 :   poDstDS->SetMetadata( pszMetadata );
    1151                 : 
    1152                 :     /* FIXME:  Should the dataset description be copied as well, or is it
    1153                 :      *         always the file name? */
    1154              24 :     poDstBand->SetDescription( poSrcBand->GetDescription() );
    1155                 : 
    1156                 :     int bSuccess;
    1157              24 :     double dfOffset = poSrcBand->GetOffset( &bSuccess );
    1158              24 :     if( bSuccess && dfOffset != 0.0 )
    1159               0 :   poDstBand->SetOffset( dfOffset );
    1160                 : 
    1161              24 :     double dfScale = poSrcBand->GetScale( &bSuccess );
    1162              24 :     if( bSuccess && dfScale != 1.0 )
    1163               0 :   poDstBand->SetScale( dfScale );
    1164                 : 
    1165              24 :     GDALColorInterp oColorInterp = poSrcBand->GetColorInterpretation();
    1166              24 :     if( oColorInterp != GCI_Undefined )
    1167              22 :         poDstBand->SetColorInterpretation( oColorInterp );
    1168                 : 
    1169              24 :     char **pszCatNames = poSrcBand->GetCategoryNames();
    1170              24 :     if( pszCatNames != NULL)
    1171               0 :   poDstBand->SetCategoryNames( pszCatNames );
    1172                 : 
    1173              24 :     GDALColorTable *poColorTable = poSrcBand->GetColorTable();
    1174              24 :     if( poColorTable != NULL )
    1175               0 :   poDstBand->SetColorTable( poColorTable );
    1176                 : 
    1177              24 :     if( !bStrict )
    1178               2 :   CPLPopErrorHandler();
    1179                 : 
    1180              24 :     return poDstDS;
    1181                 : }
    1182                 : 
    1183                 : /************************************************************************/
    1184                 : /*                               Delete()                               */
    1185                 : /************************************************************************/
    1186                 : 
    1187               4 : CPLErr GSBGDataset::Delete( const char *pszFilename )
    1188                 : 
    1189                 : {
    1190                 :     VSIStatBufL sStat;
    1191                 :     
    1192               4 :     if( VSIStatL( pszFilename, &sStat ) != 0 )
    1193                 :     {
    1194                 :   CPLError( CE_Failure, CPLE_FileIO,
    1195               0 :       "Unable to stat() %s.\n", pszFilename );
    1196               0 :   return CE_Failure;
    1197                 :     }
    1198                 :     
    1199               4 :     if( !VSI_ISREG( sStat.st_mode ) )
    1200                 :     {
    1201                 :   CPLError( CE_Failure, CPLE_FileIO,
    1202               0 :       "%s is not a regular file, not removed.\n", pszFilename );
    1203               0 :   return CE_Failure;
    1204                 :     }
    1205                 : 
    1206               4 :     if( VSIUnlink( pszFilename ) != 0 )
    1207                 :     {
    1208                 :   CPLError( CE_Failure, CPLE_FileIO,
    1209               0 :       "Error unlinking %s.\n", pszFilename );
    1210               0 :   return CE_Failure;
    1211                 :     }
    1212                 : 
    1213               4 :     return CE_None;
    1214                 : }
    1215                 : 
    1216                 : /************************************************************************/
    1217                 : /*                          GDALRegister_GSBG()                          */
    1218                 : /************************************************************************/
    1219                 : 
    1220            1135 : void GDALRegister_GSBG()
    1221                 : 
    1222                 : {
    1223                 :     GDALDriver  *poDriver;
    1224                 : 
    1225            1135 :     if( GDALGetDriverByName( "GSBG" ) == NULL )
    1226                 :     {
    1227            1093 :         poDriver = new GDALDriver();
    1228                 :         
    1229            1093 :         poDriver->SetDescription( "GSBG" );
    1230                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1231            1093 :                                    "Golden Software Binary Grid (.grd)" );
    1232                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1233            1093 :                                    "frmt_various.html#GSBG" );
    1234            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "grd" );
    1235                 :   poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
    1236            1093 :            "Byte Int16 UInt16 Float32" );
    1237            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1238                 : 
    1239            1093 :         poDriver->pfnOpen = GSBGDataset::Open;
    1240            1093 :   poDriver->pfnCreate = GSBGDataset::Create;
    1241            1093 :   poDriver->pfnCreateCopy = GSBGDataset::CreateCopy;
    1242            1093 :   poDriver->pfnDelete = GSBGDataset::Delete;
    1243                 : 
    1244            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1245                 :     }
    1246            1135 : }

Generated by: LCOV version 1.7