LCOV - code coverage report
Current view: directory - frmts/gsg - gsbgdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 476 283 59.5 %
Date: 2010-01-09 Functions: 20 17 85.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gsbgdataset.cpp 16431 2009-03-01 11:51:14Z 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 16431 2009-03-01 11:51:14Z 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              27 : {
      79                 :     friend class GSBGRasterBand;
      80                 : 
      81                 :     static const float fNODATA_VALUE;
      82                 :     static const size_t nHEADER_SIZE;
      83                 : 
      84                 :     static CPLErr WriteHeader( FILE *fp, GInt16 nXSize, GInt16 nYSize,
      85                 :              double dfMinX, double dfMaxX,
      86                 :              double dfMinY, double dfMaxY,
      87                 :              double dfMinZ, double dfMaxZ );
      88                 : 
      89                 :     FILE  *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              27 : GSBGRasterBand::GSBGRasterBand( GSBGDataset *poDS, int nBand ) :
     158                 :     pafRowMinZ(NULL),
     159                 :     pafRowMaxZ(NULL),
     160                 :     nMinZRow(-1),
     161              27 :     nMaxZRow(-1)
     162                 : 
     163                 : {
     164              27 :     this->poDS = poDS;
     165              27 :     nBand = nBand;
     166                 :     
     167              27 :     eDataType = GDT_Float32;
     168                 : 
     169              27 :     nBlockXSize = poDS->GetRasterXSize();
     170              27 :     nBlockYSize = 1;
     171              27 : }
     172                 : 
     173                 : /************************************************************************/
     174                 : /*                           ~GSBGRasterBand()                          */
     175                 : /************************************************************************/
     176                 : 
     177              54 : GSBGRasterBand::~GSBGRasterBand( )
     178                 : 
     179                 : {
     180              27 :     if( pafRowMinZ != NULL )
     181               1 :   CPLFree( pafRowMinZ );
     182              27 :     if( pafRowMaxZ != NULL )
     183               1 :   CPLFree( pafRowMaxZ );
     184              54 : }
     185                 : 
     186                 : /************************************************************************/
     187                 : /*                          ScanForMinMaxZ()                            */
     188                 : /************************************************************************/
     189                 : 
     190               1 : CPLErr GSBGRasterBand::ScanForMinMaxZ()
     191                 : 
     192                 : {
     193               1 :     float *pafRowVals = (float *)VSIMalloc2( nRasterXSize, 4 );
     194                 : 
     195               1 :     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               1 :     double dfNewMinZ = DBL_MAX;
     203               1 :     double dfNewMaxZ = -DBL_MAX;
     204               1 :     int nNewMinZRow = 0;
     205               1 :     int nNewMaxZRow = 0;
     206                 : 
     207                 :     /* Since we have to scan, lets calc. statistics too */
     208               1 :     double dfSum = 0.0;
     209               1 :     double dfSum2 = 0.0;
     210               1 :     unsigned long nValuesRead = 0;
     211              21 :     for( int iRow=0; iRow<nRasterYSize; iRow++ )
     212                 :     {
     213              20 :   CPLErr eErr = IReadBlock( 0, iRow, pafRowVals );
     214              20 :   if( eErr != CE_None )
     215                 :   {
     216               0 :       VSIFree( pafRowVals );
     217               0 :       return CE_Failure;
     218                 :   }
     219                 : 
     220              20 :   pafRowMinZ[iRow] = FLT_MAX;
     221              20 :   pafRowMaxZ[iRow] = -FLT_MAX;
     222             420 :   for( int iCol=0; iCol<nRasterXSize; iCol++ )
     223                 :   {
     224             400 :       if( pafRowVals[iCol] == GSBGDataset::fNODATA_VALUE )
     225             400 :     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              20 :   if( pafRowMinZ[iRow] < dfNewMinZ )
     239                 :   {
     240               1 :       dfNewMinZ = pafRowMinZ[iRow];
     241               1 :       nNewMinZRow = iRow;
     242                 :   }
     243                 : 
     244              20 :   if( pafRowMaxZ[iRow] > dfNewMaxZ )
     245                 :   {
     246               1 :       dfNewMaxZ = pafRowMaxZ[iRow];
     247               1 :       nNewMaxZRow = iRow;
     248                 :   }
     249                 :     }
     250                 : 
     251               1 :     VSIFree( pafRowVals );
     252                 : 
     253               1 :     if( nValuesRead == 0 )
     254                 :     {
     255               1 :   dfMinZ = 0.0;
     256               1 :   dfMaxZ = 0.0;
     257               1 :   nMinZRow = 0;
     258               1 :   nMaxZRow = 0;
     259               1 :   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             140 : CPLErr GSBGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     279                 :            void * pImage )
     280                 : 
     281                 : {
     282             140 :     if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
     283               0 :   return CE_Failure;
     284                 : 
     285             140 :     GSBGDataset *poGDS = dynamic_cast<GSBGDataset *>(poDS);
     286             140 :     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             140 :     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             140 :     pfImage = (float *)pImage;
     306             140 :     for( int iPixel=0; iPixel<nBlockXSize; iPixel++ )
     307                 :   CPL_LSBPTR32( pfImage+iPixel );
     308                 : 
     309             140 :     return CE_None;
     310                 : }
     311                 : 
     312                 : /************************************************************************/
     313                 : /*                            IWriteBlock()                             */
     314                 : /************************************************************************/
     315                 : 
     316              20 : CPLErr GSBGRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     317                 :             void *pImage )
     318                 : 
     319                 : {
     320              20 :     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              20 :     if( nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0 )
     328               0 :   return CE_Failure;
     329                 : 
     330              20 :     GSBGDataset *poGDS = dynamic_cast<GSBGDataset *>(poDS);
     331              20 :     assert( poGDS != NULL );
     332                 : 
     333              20 :     if( pafRowMinZ == NULL || pafRowMaxZ == NULL
     334                 :   || nMinZRow < 0 || nMaxZRow < 0 )
     335                 :     {
     336               1 :   pafRowMinZ = (float *)VSIMalloc2( nRasterYSize,sizeof(float) );
     337               1 :   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               1 :   pafRowMaxZ = (float *)VSIMalloc2( nRasterYSize,sizeof(float) );
     345               1 :   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               1 :   CPLErr eErr = ScanForMinMaxZ();
     355               1 :   if( eErr != CE_None )
     356               0 :       return eErr;
     357                 :     }
     358                 : 
     359              20 :     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              20 :     float *pfImage = (float *)pImage;
     370              20 :     pafRowMinZ[nBlockYOff] = FLT_MAX;
     371              20 :     pafRowMaxZ[nBlockYOff] = -FLT_MAX;
     372             420 :     for( int iPixel=0; iPixel<nBlockXSize; iPixel++ )
     373                 :     {
     374             400 :   if( pfImage[iPixel] != GSBGDataset::fNODATA_VALUE )
     375                 :   {
     376             400 :       if( pfImage[iPixel] < pafRowMinZ[nBlockYOff] )
     377              78 :     pafRowMinZ[nBlockYOff] = pfImage[iPixel];
     378                 : 
     379             400 :       if( pfImage[iPixel] > pafRowMaxZ[nBlockYOff] )
     380              43 :     pafRowMaxZ[nBlockYOff] = pfImage[iPixel];
     381                 :   }
     382                 : 
     383                 :   CPL_LSBPTR32( pfImage+iPixel );
     384                 :     }
     385                 : 
     386              20 :     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              20 :     bool bHeaderNeedsUpdate = false;
     396              20 :     if( nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ )
     397                 :     {
     398               1 :   double dfNewMinZ = DBL_MAX;
     399              21 :   for( int iRow=0; iRow<nRasterYSize; iRow++ )
     400                 :   {
     401              20 :       if( pafRowMinZ[iRow] < dfNewMinZ )
     402                 :       {
     403               1 :     dfNewMinZ = pafRowMinZ[iRow];
     404               1 :     nMinZRow = iRow;
     405                 :       }
     406                 :   }
     407                 : 
     408               1 :   if( dfNewMinZ != dfMinZ )
     409                 :   {
     410               1 :       dfMinZ = dfNewMinZ;
     411               1 :       bHeaderNeedsUpdate = true;
     412                 :   }
     413                 :     }
     414                 : 
     415              20 :     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              20 :     if( pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ )
     435                 :     {
     436               6 :   if( pafRowMinZ[nBlockYOff] < dfMinZ )
     437                 :   {
     438               3 :       dfMinZ = pafRowMinZ[nBlockYOff];
     439               3 :       nMinZRow = nBlockYOff;
     440                 :   }
     441                 : 
     442               6 :   if( pafRowMaxZ[nBlockYOff] > dfMaxZ )
     443                 :   {
     444               4 :       dfMaxZ = pafRowMaxZ[nBlockYOff];
     445               4 :       nMaxZRow = nBlockYOff;
     446                 :   }
     447                 : 
     448               6 :   bHeaderNeedsUpdate = true;
     449                 :     }
     450                 : 
     451              20 :     if( bHeaderNeedsUpdate && dfMaxZ > dfMinZ )
     452                 :     {
     453                 :   CPLErr eErr = poGDS->WriteHeader( poGDS->fp,
     454                 :             nRasterXSize, nRasterYSize,
     455                 :             dfMinX, dfMaxX,
     456                 :             dfMinY, dfMaxY,
     457               6 :             dfMinZ, dfMaxZ );
     458               6 :   return eErr;
     459                 :     }
     460                 : 
     461              14 :     return CE_None;
     462                 : }
     463                 : 
     464                 : /************************************************************************/
     465                 : /*                           GetNoDataValue()                           */
     466                 : /************************************************************************/
     467                 : 
     468               7 : double GSBGRasterBand::GetNoDataValue( int * pbSuccess )
     469                 : {
     470               7 :     if( pbSuccess )
     471               7 :         *pbSuccess = TRUE;
     472                 : 
     473               7 :     return GSBGDataset::fNODATA_VALUE;
     474                 : }
     475                 : 
     476                 : /************************************************************************/
     477                 : /*                             GetMinimum()                             */
     478                 : /************************************************************************/
     479                 : 
     480               0 : double GSBGRasterBand::GetMinimum( int *pbSuccess )
     481                 : {
     482               0 :     if( pbSuccess )
     483               0 :         *pbSuccess = TRUE;
     484                 : 
     485               0 :     return dfMinZ;
     486                 : }
     487                 : 
     488                 : /************************************************************************/
     489                 : /*                             GetMaximum()                             */
     490                 : /************************************************************************/
     491                 : 
     492               0 : double GSBGRasterBand::GetMaximum( int *pbSuccess )
     493                 : {
     494               0 :     if( pbSuccess )
     495               0 :         *pbSuccess = TRUE;
     496                 : 
     497               0 :     return dfMaxZ;
     498                 : }
     499                 : 
     500                 : /************************************************************************/
     501                 : /* ==================================================================== */
     502                 : /*        GSBGDataset       */
     503                 : /* ==================================================================== */
     504                 : /************************************************************************/
     505                 : 
     506              54 : GSBGDataset::~GSBGDataset()
     507                 : 
     508                 : {
     509              27 :     FlushCache();
     510              27 :     if( fp != NULL )
     511              27 :         VSIFCloseL( fp );
     512              54 : }
     513                 : 
     514                 : /************************************************************************/
     515                 : /*                                Open()                                */
     516                 : /************************************************************************/
     517                 : 
     518            8812 : GDALDataset *GSBGDataset::Open( GDALOpenInfo * poOpenInfo )
     519                 : 
     520                 : {
     521                 :     /* Check for signature */
     522            8812 :     if( poOpenInfo->nHeaderBytes < 4
     523                 :   || !EQUALN((const char *) poOpenInfo->pabyHeader,"DSBB",4) )
     524                 :     {
     525            8785 :         return NULL;
     526                 :     }
     527                 : 
     528                 : /* -------------------------------------------------------------------- */
     529                 : /*      Create a corresponding GDALDataset.                             */
     530                 : /* -------------------------------------------------------------------- */
     531              27 :     GSBGDataset *poDS = new GSBGDataset();
     532                 : 
     533                 : /* -------------------------------------------------------------------- */
     534                 : /*      Open file with large file API.                                  */
     535                 : /* -------------------------------------------------------------------- */
     536              27 :     poDS->eAccess = poOpenInfo->eAccess;
     537              27 :     if( poOpenInfo->eAccess == GA_ReadOnly )
     538               5 :       poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     539                 :     else
     540              22 :       poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
     541                 : 
     542              27 :     if( poDS->fp == NULL )
     543                 :     {
     544               0 :   delete poDS;
     545                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     546                 :                   "VSIFOpenL(%s) failed unexpectedly.", 
     547               0 :                   poOpenInfo->pszFilename );
     548               0 :         return NULL;
     549                 :     }
     550                 :  
     551                 : /* -------------------------------------------------------------------- */
     552                 : /*      Read the header.                                                */
     553                 : /* -------------------------------------------------------------------- */
     554              27 :     if( VSIFSeekL( poDS->fp, 4, SEEK_SET ) != 0 )
     555                 :     {
     556               0 :   delete poDS;
     557                 :   CPLError( CE_Failure, CPLE_FileIO,
     558               0 :       "Unable to seek to start of grid file header.\n" );
     559               0 :   return NULL;
     560                 :     }
     561                 : 
     562                 :     /* Parse number of X axis grid rows */
     563                 :     GInt16 nTemp;
     564              27 :     if( VSIFReadL( (void *)&nTemp, 2, 1, poDS->fp ) != 1 )
     565                 :     {
     566               0 :   delete poDS;
     567               0 :   CPLError( CE_Failure, CPLE_FileIO, "Unable to read raster X size.\n" );
     568               0 :   return NULL;
     569                 :     }
     570              27 :     poDS->nRasterXSize = CPL_LSBWORD16( nTemp );
     571                 : 
     572              27 :     if( VSIFReadL( (void *)&nTemp, 2, 1, poDS->fp ) != 1 )
     573                 :     {
     574               0 :   delete poDS;
     575               0 :   CPLError( CE_Failure, CPLE_FileIO, "Unable to read raster Y size.\n" );
     576               0 :   return NULL;
     577                 :     }
     578              27 :     poDS->nRasterYSize = CPL_LSBWORD16( nTemp );
     579                 : 
     580              27 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     581                 :     {
     582               0 :         delete poDS;
     583               0 :         return NULL;
     584                 :     }
     585                 : 
     586                 : /* -------------------------------------------------------------------- */
     587                 : /*      Create band information objects.                                */
     588                 : /* -------------------------------------------------------------------- */
     589              27 :     GSBGRasterBand *poBand = new GSBGRasterBand( poDS, 1 );
     590                 : 
     591                 :     double dfTemp;
     592              27 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     593                 :     {
     594               0 :   delete poDS;
     595                 :   CPLError( CE_Failure, CPLE_FileIO,
     596               0 :       "Unable to read minimum X value.\n" );
     597               0 :   return NULL;
     598                 :     }
     599                 :     CPL_LSBPTR64( &dfTemp );
     600              27 :     poBand->dfMinX = dfTemp;
     601                 : 
     602              27 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     603                 :     {
     604               0 :   delete poDS;
     605                 :   CPLError( CE_Failure, CPLE_FileIO,
     606               0 :       "Unable to read maximum X value.\n" );
     607               0 :   return NULL;
     608                 :     }
     609                 :     CPL_LSBPTR64( &dfTemp );
     610              27 :     poBand->dfMaxX = dfTemp;
     611                 : 
     612              27 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     613                 :     {
     614               0 :   delete poDS;
     615                 :   CPLError( CE_Failure, CPLE_FileIO,
     616               0 :       "Unable to read minimum Y value.\n" );
     617               0 :   return NULL;
     618                 :     }
     619                 :     CPL_LSBPTR64( &dfTemp );
     620              27 :     poBand->dfMinY = dfTemp;
     621                 : 
     622              27 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     623                 :     {
     624               0 :   delete poDS;
     625                 :   CPLError( CE_Failure, CPLE_FileIO,
     626               0 :       "Unable to read maximum Y value.\n" );
     627               0 :   return NULL;
     628                 :     }
     629                 :     CPL_LSBPTR64( &dfTemp );
     630              27 :     poBand->dfMaxY = dfTemp;
     631                 : 
     632              27 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     633                 :     {
     634               0 :   delete poDS;
     635                 :   CPLError( CE_Failure, CPLE_FileIO,
     636               0 :       "Unable to read minimum Z value.\n" );
     637               0 :   return NULL;
     638                 :     }
     639                 :     CPL_LSBPTR64( &dfTemp );
     640              27 :     poBand->dfMinZ = dfTemp;
     641                 : 
     642              27 :     if( VSIFReadL( (void *)&dfTemp, 8, 1, poDS->fp ) != 1 )
     643                 :     {
     644               0 :   delete poDS;
     645                 :   CPLError( CE_Failure, CPLE_FileIO,
     646               0 :       "Unable to read maximum Z value.\n" );
     647               0 :   return NULL;
     648                 :     }
     649                 :     CPL_LSBPTR64( &dfTemp );
     650              27 :     poBand->dfMaxZ = dfTemp;
     651                 : 
     652              27 :     poDS->SetBand( 1, poBand );
     653                 : 
     654                 : /* -------------------------------------------------------------------- */
     655                 : /*      Initialize any PAM information.                                 */
     656                 : /* -------------------------------------------------------------------- */
     657              27 :     poDS->SetDescription( poOpenInfo->pszFilename );
     658              27 :     poDS->TryLoadXML();
     659                 : 
     660              27 :     return poDS;
     661                 : }
     662                 : 
     663                 : /************************************************************************/
     664                 : /*                          GetGeoTransform()                           */
     665                 : /************************************************************************/
     666                 : 
     667               4 : CPLErr GSBGDataset::GetGeoTransform( double *padfGeoTransform )
     668                 : {
     669               4 :     if( padfGeoTransform == NULL )
     670               0 :   return CE_Failure;
     671                 : 
     672               4 :     GSBGRasterBand *poGRB = dynamic_cast<GSBGRasterBand *>(GetRasterBand( 1 ));
     673                 : 
     674               4 :     if( poGRB == NULL )
     675                 :     {
     676               0 :   padfGeoTransform[0] = 0;
     677               0 :   padfGeoTransform[1] = 1;
     678               0 :   padfGeoTransform[2] = 0;
     679               0 :   padfGeoTransform[3] = 0;
     680               0 :   padfGeoTransform[4] = 0;
     681               0 :   padfGeoTransform[5] = 1;
     682               0 :   return CE_Failure;
     683                 :     }
     684                 : 
     685                 :     /* check if we have a PAM GeoTransform stored */
     686               4 :     CPLPushErrorHandler( CPLQuietErrorHandler );
     687               4 :     CPLErr eErr = GDALPamDataset::GetGeoTransform( padfGeoTransform );
     688               4 :     CPLPopErrorHandler();
     689                 : 
     690               4 :     if( eErr == CE_None )
     691               0 :   return CE_None;
     692                 : 
     693                 :     /* calculate pixel size first */
     694               4 :     padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX)/(nRasterXSize - 1);
     695               4 :     padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY)/(nRasterYSize - 1);
     696                 : 
     697                 :     /* then calculate image origin */
     698               4 :     padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2;
     699               4 :     padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2;
     700                 : 
     701                 :     /* tilt/rotation does not supported by the GS grids */
     702               4 :     padfGeoTransform[4] = 0.0;
     703               4 :     padfGeoTransform[2] = 0.0;
     704                 : 
     705               4 :     return CE_None;
     706                 : }
     707                 : 
     708                 : /************************************************************************/
     709                 : /*                          SetGeoTransform()                           */
     710                 : /************************************************************************/
     711                 : 
     712               0 : CPLErr GSBGDataset::SetGeoTransform( double *padfGeoTransform )
     713                 : {
     714               0 :     if( eAccess == GA_ReadOnly )
     715                 :     {
     716                 :   CPLError( CE_Failure, CPLE_NoWriteAccess,
     717               0 :       "Unable to set GeoTransform, dataset opened read only.\n" );
     718               0 :   return CE_Failure;
     719                 :     }
     720                 : 
     721               0 :     GSBGRasterBand *poGRB = dynamic_cast<GSBGRasterBand *>(GetRasterBand( 1 ));
     722                 : 
     723               0 :     if( poGRB == NULL || padfGeoTransform == NULL)
     724               0 :   return CE_Failure;
     725                 : 
     726                 :     /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
     727               0 :     CPLErr eErr = CE_None;
     728                 :     /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0
     729                 :   || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 )
     730                 :   eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform );
     731                 : 
     732                 :     if( eErr != CE_None )
     733                 :   return eErr;*/
     734                 : 
     735               0 :     double dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2;
     736                 :     double dfMaxX =
     737               0 :         padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0];
     738                 :     double dfMinY =
     739               0 :         padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3];
     740               0 :     double dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2;
     741                 : 
     742                 :     eErr = WriteHeader( fp, poGRB->nRasterXSize, poGRB->nRasterYSize,
     743                 :       dfMinX, dfMaxX, dfMinY, dfMaxY,
     744               0 :       poGRB->dfMinZ, poGRB->dfMaxZ );
     745                 : 
     746               0 :     if( eErr == CE_None )
     747                 :     {
     748               0 :   poGRB->dfMinX = dfMinX;
     749               0 :   poGRB->dfMaxX = dfMaxX;
     750               0 :   poGRB->dfMinY = dfMinY;
     751               0 :   poGRB->dfMaxY = dfMaxY;
     752                 :     }
     753                 : 
     754               0 :     return eErr;
     755                 : }
     756                 : 
     757                 : /************************************************************************/
     758                 : /*                             WriteHeader()                            */
     759                 : /************************************************************************/
     760                 : 
     761              40 : CPLErr GSBGDataset::WriteHeader( FILE *fp, GInt16 nXSize, GInt16 nYSize,
     762                 :          double dfMinX, double dfMaxX,
     763                 :          double dfMinY, double dfMaxY,
     764                 :          double dfMinZ, double dfMaxZ )
     765                 : 
     766                 : {
     767              40 :     if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
     768                 :     {
     769                 :   CPLError( CE_Failure, CPLE_FileIO,
     770               0 :       "Unable to seek to start of grid file.\n" );
     771               0 :   return CE_Failure;
     772                 :     }
     773                 : 
     774              40 :     if( VSIFWriteL( (void *)"DSBB", 1, 4, fp ) != 4 )
     775                 :     {
     776                 :   CPLError( CE_Failure, CPLE_FileIO,
     777               0 :       "Unable to write signature to grid file.\n" );
     778               0 :   return CE_Failure;
     779                 :     }
     780                 : 
     781              40 :     GInt16 nTemp = CPL_LSBWORD16(nXSize);
     782              40 :     if( VSIFWriteL( (void *)&nTemp, 2, 1, fp ) != 1 )
     783                 :     {
     784                 :   CPLError( CE_Failure, CPLE_FileIO,
     785               0 :       "Unable to write raster X size to grid file.\n" );
     786               0 :   return CE_Failure;
     787                 :     }
     788                 : 
     789              40 :     nTemp = CPL_LSBWORD16(nYSize);
     790              40 :     if( VSIFWriteL( (void *)&nTemp, 2, 1, fp ) != 1 )
     791                 :     {
     792                 :   CPLError( CE_Failure, CPLE_FileIO,
     793               0 :       "Unable to write raster Y size to grid file.\n" );
     794               0 :   return CE_Failure;
     795                 :     }
     796                 : 
     797              40 :     double dfTemp = dfMinX;
     798                 :     CPL_LSBPTR64( &dfTemp );
     799              40 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     800                 :     {
     801                 :   CPLError( CE_Failure, CPLE_FileIO,
     802               0 :       "Unable to write minimum X value to grid file.\n" );
     803               0 :   return CE_Failure;
     804                 :     }
     805                 : 
     806              40 :     dfTemp = dfMaxX;
     807                 :     CPL_LSBPTR64( &dfTemp );
     808              40 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     809                 :     {
     810                 :   CPLError( CE_Failure, CPLE_FileIO,
     811               0 :       "Unable to write maximum X value to grid file.\n" );
     812               0 :   return CE_Failure;
     813                 :     }
     814                 : 
     815              40 :     dfTemp = dfMinY;
     816                 :     CPL_LSBPTR64( &dfTemp );
     817              40 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     818                 :     {
     819                 :   CPLError( CE_Failure, CPLE_FileIO,
     820               0 :       "Unable to write minimum Y value to grid file.\n" );
     821               0 :   return CE_Failure;
     822                 :     }
     823                 : 
     824              40 :     dfTemp = dfMaxY;
     825                 :     CPL_LSBPTR64( &dfTemp );
     826              40 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     827                 :     {
     828                 :   CPLError( CE_Failure, CPLE_FileIO,
     829               0 :       "Unable to write maximum Y value to grid file.\n" );
     830               0 :   return CE_Failure;
     831                 :     }
     832                 : 
     833              40 :     dfTemp = dfMinZ;
     834                 :     CPL_LSBPTR64( &dfTemp );
     835              40 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     836                 :     {
     837                 :   CPLError( CE_Failure, CPLE_FileIO,
     838               0 :       "Unable to write minimum Z value to grid file.\n" );
     839               0 :   return CE_Failure;
     840                 :     }
     841                 : 
     842              40 :     dfTemp = dfMaxZ;
     843                 :     CPL_LSBPTR64( &dfTemp );
     844              40 :     if( VSIFWriteL( (void *)&dfTemp, 8, 1, fp ) != 1 )
     845                 :     {
     846                 :   CPLError( CE_Failure, CPLE_FileIO,
     847               0 :       "Unable to write maximum Z value to grid file.\n" );
     848               0 :   return CE_Failure;
     849                 :     }
     850                 : 
     851              40 :     return CE_None;
     852                 : }
     853                 : 
     854                 : /************************************************************************/
     855                 : /*                               Create()                               */
     856                 : /************************************************************************/
     857                 : 
     858              17 : GDALDataset *GSBGDataset::Create( const char * pszFilename,
     859                 :           int nXSize, int nYSize, int nBands,
     860                 :           GDALDataType eType,
     861                 :           char **papszParmList )
     862                 : 
     863                 : {
     864              17 :     if( nXSize <= 0 || nYSize <= 0 )
     865                 :     {
     866                 :   CPLError( CE_Failure, CPLE_IllegalArg,
     867                 :       "Unable to create grid, both X and Y size must be "
     868               0 :       "non-negative.\n" );
     869                 : 
     870               0 :   return NULL;
     871                 :     }
     872              17 :     else if( nXSize > SHRT_MAX
     873                 :        || nYSize > SHRT_MAX )
     874                 :     {
     875                 :   CPLError( CE_Failure, CPLE_IllegalArg,
     876                 :       "Unable to create grid, Golden Software Binary Grid format "
     877                 :       "only supports sizes up to %dx%d.  %dx%d not supported.\n",
     878               0 :       SHRT_MAX, SHRT_MAX, nXSize, nYSize );
     879                 : 
     880               0 :   return NULL;
     881                 :     }
     882                 : 
     883              17 :     if( eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16
     884                 :         && eType != GDT_Int16 )
     885                 :     {
     886                 :         CPLError( CE_Failure, CPLE_AppDefined,
     887                 :       "Golden Software ASCII Grid only supports Byte, Int16, "
     888                 :       "Uint16, and Float32 datatypes.  Unable to create with "
     889               7 :       "type %s.\n", GDALGetDataTypeName( eType ) );
     890                 : 
     891               7 :         return NULL;
     892                 :     }
     893                 : 
     894              10 :     FILE *fp = VSIFOpenL( pszFilename, "w+b" );
     895                 : 
     896              10 :     if( fp == NULL )
     897                 :     {
     898                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     899                 :                   "Attempt to create file '%s' failed.\n",
     900               0 :                   pszFilename );
     901               0 :         return NULL;
     902                 :     }
     903                 : 
     904                 :     CPLErr eErr = WriteHeader( fp, nXSize, nYSize,
     905              10 :              0.0, nXSize, 0.0, nYSize, 0.0, 0.0 );
     906              10 :     if( eErr != CE_None )
     907                 :     {
     908               0 :   VSIFCloseL( fp );
     909               0 :   return NULL;
     910                 :     }
     911                 : 
     912              10 :     float fVal = fNODATA_VALUE;
     913                 :     CPL_LSBPTR32( &fVal );
     914             930 :     for( int iRow = 0; iRow < nYSize; iRow++ )
     915                 :     {
     916           91320 :   for( int iCol=0; iCol<nXSize; iCol++ )
     917                 :   {
     918           90400 :       if( VSIFWriteL( (void *)&fVal, 4, 1, fp ) != 1 )
     919                 :       {
     920               0 :     VSIFCloseL( fp );
     921                 :     CPLError( CE_Failure, CPLE_FileIO,
     922               0 :         "Unable to write grid cell.  Disk full?\n" );
     923               0 :     return NULL;
     924                 :       }
     925                 :   }
     926                 :     }
     927                 : 
     928              10 :     VSIFCloseL( fp );
     929                 : 
     930              10 :     return (GDALDataset *)GDALOpen( pszFilename, GA_Update );
     931                 : }
     932                 : 
     933                 : /************************************************************************/
     934                 : /*                             CreateCopy()                             */
     935                 : /************************************************************************/
     936                 : 
     937              17 : GDALDataset *GSBGDataset::CreateCopy( const char *pszFilename,
     938                 :               GDALDataset *poSrcDS,
     939                 :               int bStrict, char **papszOptions,
     940                 :               GDALProgressFunc pfnProgress,
     941                 :               void *pProgressData )
     942                 : {
     943              17 :     if( pfnProgress == NULL )
     944               0 :   pfnProgress = GDALDummyProgress;
     945                 : 
     946              17 :     int nBands = poSrcDS->GetRasterCount();
     947              17 :     if (nBands == 0)
     948                 :     {
     949                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     950               1 :                   "GSBG driver does not support source dataset with zero band.\n");
     951               1 :         return NULL;
     952                 :     }
     953              16 :     else if (nBands > 1)
     954                 :     {
     955               4 :   if( bStrict )
     956                 :   {
     957                 :       CPLError( CE_Failure, CPLE_NotSupported,
     958                 :           "Unable to create copy, Golden Software Binary Grid "
     959               4 :           "format only supports one raster band.\n" );
     960               4 :       return NULL;
     961                 :   }
     962                 :   else
     963                 :       CPLError( CE_Warning, CPLE_NotSupported,
     964                 :           "Golden Software Binary Grid format only supports one "
     965               0 :           "raster band, first band will be copied.\n" );
     966                 :     }
     967                 : 
     968              12 :     GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( 1 );
     969              12 :     if( poSrcBand->GetXSize() > SHRT_MAX
     970                 :   || poSrcBand->GetYSize() > SHRT_MAX )
     971                 :     {
     972                 :   CPLError( CE_Failure, CPLE_IllegalArg,
     973                 :       "Unable to create grid, Golden Software Binary Grid format "
     974                 :       "only supports sizes up to %dx%d.  %dx%d not supported.\n",
     975                 :       SHRT_MAX, SHRT_MAX,
     976               0 :       poSrcBand->GetXSize(), poSrcBand->GetYSize() );
     977                 : 
     978               0 :   return NULL;
     979                 :     }
     980                 : 
     981              12 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
     982                 :     {
     983               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated\n" );
     984               0 :         return NULL;
     985                 :     }
     986                 : 
     987              12 :     FILE    *fp = VSIFOpenL( pszFilename, "w+b" );
     988                 : 
     989              12 :     if( fp == NULL )
     990                 :     {
     991                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     992                 :                   "Attempt to create file '%s' failed.\n",
     993               0 :                   pszFilename );
     994               0 :         return NULL;
     995                 :     }
     996                 : 
     997              12 :     GInt16  nXSize = poSrcBand->GetXSize();
     998              12 :     GInt16  nYSize = poSrcBand->GetYSize();
     999                 :     double  adfGeoTransform[6];
    1000                 : 
    1001              12 :     poSrcDS->GetGeoTransform( adfGeoTransform );
    1002                 : 
    1003              12 :     double dfMinX = adfGeoTransform[0] + adfGeoTransform[1] / 2;
    1004              12 :     double dfMaxX = adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0];
    1005              12 :     double dfMinY = adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3];
    1006              12 :     double dfMaxY = adfGeoTransform[3] + adfGeoTransform[5] / 2;
    1007                 :     CPLErr eErr = WriteHeader( fp, nXSize, nYSize,
    1008              12 :              dfMinX, dfMaxX, dfMinY, dfMaxY, 0.0, 0.0 );
    1009                 : 
    1010              12 :     if( eErr != CE_None )
    1011                 :     {
    1012               0 :   VSIFCloseL( fp );
    1013               0 :         return NULL;
    1014                 :     }
    1015                 : 
    1016                 : /* -------------------------------------------------------------------- */
    1017                 : /*      Copy band data.             */
    1018                 : /* -------------------------------------------------------------------- */
    1019              12 :     float *pfData = (float *)VSIMalloc2( nXSize, sizeof( float ) );
    1020              12 :     if( pfData == NULL )
    1021                 :     {
    1022               0 :   VSIFCloseL( fp );
    1023                 :   CPLError( CE_Failure, CPLE_OutOfMemory,
    1024               0 :       "Unable to create copy, unable to allocate line buffer.\n" );
    1025               0 :   return NULL;
    1026                 :     }
    1027                 : 
    1028                 :     int     bSrcHasNDValue;
    1029              12 :     float   fSrcNoDataValue = poSrcBand->GetNoDataValue( &bSrcHasNDValue );
    1030              12 :     double  dfMinZ = DBL_MAX;
    1031              12 :     double  dfMaxZ = -DBL_MAX;
    1032             142 :     for( GInt16 iRow = nYSize - 1; iRow >= 0; iRow-- )
    1033                 :     {
    1034                 :   eErr = poSrcBand->RasterIO( GF_Read, 0, iRow,
    1035                 :             nXSize, 1, pfData,
    1036             130 :             nXSize, 1, GDT_Float32, 0, 0 );
    1037                 : 
    1038             130 :   if( eErr != CE_None )
    1039                 :   {
    1040               0 :       VSIFCloseL( fp );
    1041               0 :       VSIFree( pfData );
    1042               0 :       return NULL;
    1043                 :   }
    1044                 : 
    1045            1630 :   for( int iCol=0; iCol<nXSize; iCol++ )
    1046                 :   {
    1047            1500 :       if( bSrcHasNDValue && pfData[iCol] == fSrcNoDataValue )
    1048                 :       {
    1049               0 :     pfData[iCol] = fNODATA_VALUE;
    1050                 :       }
    1051                 :       else
    1052                 :       {
    1053            1500 :     if( pfData[iCol] > dfMaxZ )
    1054              14 :         dfMaxZ = pfData[iCol];
    1055                 : 
    1056            1500 :     if( pfData[iCol] < dfMinZ )
    1057              19 :         dfMinZ = pfData[iCol];
    1058                 :       }
    1059                 : 
    1060                 :       CPL_LSBPTR32( pfData+iCol );
    1061                 :   }
    1062                 : 
    1063             130 :   if( VSIFWriteL( (void *)pfData, 4, nXSize,
    1064                 :       fp ) != static_cast<unsigned>(nXSize) )
    1065                 :   {
    1066               0 :       VSIFCloseL( fp );
    1067               0 :       VSIFree( pfData );
    1068                 :       CPLError( CE_Failure, CPLE_FileIO,
    1069               0 :           "Unable to write grid row. Disk full?\n" );
    1070               0 :       return NULL;
    1071                 :   }
    1072                 : 
    1073             130 :   if( !pfnProgress( static_cast<double>(iRow)/nYSize,
    1074                 :         NULL, pProgressData ) )
    1075                 :   {
    1076               0 :       VSIFCloseL( fp );
    1077               0 :       VSIFree( pfData );
    1078               0 :       CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1079               0 :       return NULL;
    1080                 :   }
    1081                 :     }
    1082                 : 
    1083              12 :     VSIFree( pfData );
    1084                 : 
    1085                 :     /* write out the min and max values */
    1086                 :     eErr = WriteHeader( fp, nXSize, nYSize,
    1087              12 :       dfMinX, dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ );
    1088                 : 
    1089              12 :     if( eErr != CE_None )
    1090                 :     {
    1091               0 :   VSIFCloseL( fp );
    1092               0 :         return NULL;
    1093                 :     }
    1094                 : 
    1095              12 :     VSIFCloseL( fp );
    1096                 : 
    1097                 :     GDALPamDataset *poDstDS = (GDALPamDataset *)GDALOpen( pszFilename,
    1098              12 :                 GA_Update );
    1099              12 :     if( poDstDS == NULL )
    1100                 :     {
    1101               0 :   VSIUnlink( pszFilename );
    1102                 :   CPLError( CE_Failure, CPLE_FileIO,
    1103               0 :       "Unable to open copy of dataset.\n" );
    1104               0 :   return NULL;
    1105                 :     }
    1106              12 :     else if( dynamic_cast<GSBGDataset *>(poDstDS) == NULL )
    1107                 :     {
    1108               0 :   VSIUnlink( pszFilename );
    1109               0 :   delete poDstDS;
    1110                 :   CPLError( CE_Failure, CPLE_FileIO,
    1111               0 :       "Copy dataset not opened as Golden Surfer Binary Grid!?\n" );
    1112               0 :   return NULL;
    1113                 :     }
    1114                 : 
    1115              12 :     GDALRasterBand *poDstBand = poSrcDS->GetRasterBand(1);
    1116              12 :     if( poDstBand == NULL )
    1117                 :     {
    1118               0 :   VSIUnlink( pszFilename );
    1119               0 :   delete poDstDS;
    1120                 :   CPLError( CE_Failure, CPLE_FileIO,
    1121               0 :       "Unable to open copy of raster band?\n" );
    1122               0 :   return NULL;
    1123                 :     }
    1124                 : 
    1125                 : /* -------------------------------------------------------------------- */
    1126                 : /*      Attempt to copy metadata.         */
    1127                 : /* -------------------------------------------------------------------- */
    1128              12 :     if( !bStrict )
    1129               1 :   CPLPushErrorHandler( CPLQuietErrorHandler );
    1130                 : 
    1131                 :     /* non-zero transform 2 or 4 or negative 1 or 5  not supported natively */
    1132                 :     /*if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0
    1133                 :   || adfGeoTransform[1] < 0.0 || adfGeoTransform[5] < 0.0 )
    1134                 :   poDstDS->GDALPamDataset::SetGeoTransform( adfGeoTransform );*/
    1135                 : 
    1136              12 :     const char *szProjectionRef = poSrcDS->GetProjectionRef();
    1137              12 :     if( *szProjectionRef != '\0' )
    1138              11 :   poDstDS->SetProjection( szProjectionRef );
    1139                 : 
    1140              12 :     char **pszMetadata = poSrcDS->GetMetadata();
    1141              12 :     if( pszMetadata != NULL )
    1142              11 :   poDstDS->SetMetadata( pszMetadata );
    1143                 : 
    1144                 :     /* FIXME:  Should the dataset description be copied as well, or is it
    1145                 :      *         always the file name? */
    1146              12 :     poDstBand->SetDescription( poSrcBand->GetDescription() );
    1147                 : 
    1148                 :     int bSuccess;
    1149              12 :     double dfOffset = poSrcBand->GetOffset( &bSuccess );
    1150              12 :     if( bSuccess && dfOffset != 0.0 )
    1151               0 :   poDstBand->SetOffset( dfOffset );
    1152                 : 
    1153              12 :     double dfScale = poSrcBand->GetScale( &bSuccess );
    1154              12 :     if( bSuccess && dfScale != 1.0 )
    1155               0 :   poDstBand->SetScale( dfScale );
    1156                 : 
    1157              12 :     GDALColorInterp oColorInterp = poSrcBand->GetColorInterpretation();
    1158              12 :     if( oColorInterp != GCI_Undefined )
    1159              11 :         poDstBand->SetColorInterpretation( oColorInterp );
    1160                 : 
    1161              12 :     char **pszCatNames = poSrcBand->GetCategoryNames();
    1162              12 :     if( pszCatNames != NULL)
    1163               0 :   poDstBand->SetCategoryNames( pszCatNames );
    1164                 : 
    1165              12 :     GDALColorTable *poColorTable = poSrcBand->GetColorTable();
    1166              12 :     if( poColorTable != NULL )
    1167               0 :   poDstBand->SetColorTable( poColorTable );
    1168                 : 
    1169              12 :     if( !bStrict )
    1170               1 :   CPLPopErrorHandler();
    1171                 : 
    1172              12 :     return poDstDS;
    1173                 : }
    1174                 : 
    1175                 : /************************************************************************/
    1176                 : /*                               Delete()                               */
    1177                 : /************************************************************************/
    1178                 : 
    1179               2 : CPLErr GSBGDataset::Delete( const char *pszFilename )
    1180                 : 
    1181                 : {
    1182                 :     VSIStatBufL sStat;
    1183                 :     
    1184               2 :     if( VSIStatL( pszFilename, &sStat ) != 0 )
    1185                 :     {
    1186                 :   CPLError( CE_Failure, CPLE_FileIO,
    1187               0 :       "Unable to stat() %s.\n", pszFilename );
    1188               0 :   return CE_Failure;
    1189                 :     }
    1190                 :     
    1191               2 :     if( !VSI_ISREG( sStat.st_mode ) )
    1192                 :     {
    1193                 :   CPLError( CE_Failure, CPLE_FileIO,
    1194               0 :       "%s is not a regular file, not removed.\n", pszFilename );
    1195               0 :   return CE_Failure;
    1196                 :     }
    1197                 : 
    1198               2 :     if( VSIUnlink( pszFilename ) != 0 )
    1199                 :     {
    1200                 :   CPLError( CE_Failure, CPLE_FileIO,
    1201               0 :       "Error unlinking %s.\n", pszFilename );
    1202               0 :   return CE_Failure;
    1203                 :     }
    1204                 : 
    1205               2 :     return CE_None;
    1206                 : }
    1207                 : 
    1208                 : /************************************************************************/
    1209                 : /*                          GDALRegister_GSBG()                          */
    1210                 : /************************************************************************/
    1211                 : 
    1212             338 : void GDALRegister_GSBG()
    1213                 : 
    1214                 : {
    1215                 :     GDALDriver  *poDriver;
    1216                 : 
    1217             338 :     if( GDALGetDriverByName( "GSBG" ) == NULL )
    1218                 :     {
    1219             336 :         poDriver = new GDALDriver();
    1220                 :         
    1221             336 :         poDriver->SetDescription( "GSBG" );
    1222                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1223             336 :                                    "Golden Software Binary Grid (.grd)" );
    1224                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1225             336 :                                    "frmt_various.html#GSBG" );
    1226             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "grd" );
    1227                 :   poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
    1228             336 :            "Byte Int16 UInt16 Float32" );
    1229                 : 
    1230             336 :         poDriver->pfnOpen = GSBGDataset::Open;
    1231             336 :   poDriver->pfnCreate = GSBGDataset::Create;
    1232             336 :   poDriver->pfnCreateCopy = GSBGDataset::CreateCopy;
    1233             336 :   poDriver->pfnDelete = GSBGDataset::Delete;
    1234                 : 
    1235             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1236                 :     }
    1237             338 : }

Generated by: LCOV version 1.7