LCOV - code coverage report
Current view: directory - frmts/raw - btdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 334 253 75.7 %
Date: 2012-04-28 Functions: 24 15 62.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: btdataset.cpp 23033 2011-09-03 18:46:11Z rouault $
       3                 :  *
       4                 :  * Project:  VTP .bt Driver
       5                 :  * Purpose:  Implementation of VTP .bt elevation format read/write support.
       6                 :  *           http://www.vterrain.org/Implementation/Formats/BT.html
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2003, Frank Warmerdam
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "rawdataset.h"
      32                 : #include "ogr_spatialref.h"
      33                 : 
      34                 : CPL_CVSID("$Id: btdataset.cpp 23033 2011-09-03 18:46:11Z rouault $");
      35                 : 
      36                 : CPL_C_START
      37                 : void    GDALRegister_BT(void);
      38                 : CPL_C_END
      39                 : 
      40                 : /************************************************************************/
      41                 : /* ==================================================================== */
      42                 : /*                              BTDataset                               */
      43                 : /* ==================================================================== */
      44                 : /************************************************************************/
      45                 : 
      46                 : class BTDataset : public GDALPamDataset
      47                 : {
      48                 :     friend class BTRasterBand;
      49                 : 
      50                 :     VSILFILE        *fpImage;       // image data file.
      51                 : 
      52                 :     int         bGeoTransformValid;
      53                 :     double      adfGeoTransform[6];
      54                 : 
      55                 :     char        *pszProjection;
      56                 :     
      57                 :     double      dfVScale;
      58                 : 
      59                 :     int         nVersionCode;  // version times 10.
      60                 : 
      61                 :     int         bHeaderModified;
      62                 :     unsigned char abyHeader[256];
      63                 : 
      64                 :     float        m_fVscale;
      65                 : 
      66                 :   public:
      67                 : 
      68                 :                 BTDataset();
      69                 :                 ~BTDataset();
      70                 : 
      71                 :     virtual const char *GetProjectionRef(void);
      72                 :     virtual CPLErr SetProjection( const char * );
      73                 :     virtual CPLErr GetGeoTransform( double * );
      74                 :     virtual CPLErr SetGeoTransform( double * );
      75                 : 
      76                 :     virtual void   FlushCache();
      77                 : 
      78                 :     static GDALDataset *Open( GDALOpenInfo * );
      79                 :     static GDALDataset *Create( const char * pszFilename,
      80                 :                                 int nXSize, int nYSize, int nBands,
      81                 :                                 GDALDataType eType, char ** papszOptions );
      82                 : };
      83                 : 
      84                 : /************************************************************************/
      85                 : /* ==================================================================== */
      86                 : /*                            BTRasterBand                              */
      87                 : /* ==================================================================== */
      88                 : /************************************************************************/
      89                 : 
      90                 : class BTRasterBand : public GDALPamRasterBand
      91              54 : {
      92                 :     VSILFILE          *fpImage;
      93                 : 
      94                 :   public:
      95                 : 
      96                 :                    BTRasterBand( GDALDataset * poDS, VSILFILE * fp,
      97                 :                                  GDALDataType eType );
      98                 : 
      99                 :     virtual CPLErr IReadBlock( int, int, void * );
     100                 :     virtual CPLErr IWriteBlock( int, int, void * );
     101                 : 
     102                 :     virtual const char* GetUnitType();
     103                 :     virtual CPLErr SetUnitType(const char*);
     104                 :   virtual double GetNoDataValue( int* = NULL );
     105                 :     virtual CPLErr SetNoDataValue( double );
     106                 : };
     107                 : 
     108                 : 
     109                 : /************************************************************************/
     110                 : /*                           BTRasterBand()                             */
     111                 : /************************************************************************/
     112                 : 
     113              54 : BTRasterBand::BTRasterBand( GDALDataset *poDS, VSILFILE *fp, GDALDataType eType )
     114                 : 
     115                 : {
     116              54 :     this->poDS = poDS;
     117              54 :     this->nBand = 1;
     118              54 :     this->eDataType = eType;
     119              54 :     this->fpImage = fp;
     120                 : 
     121              54 :     nBlockXSize = 1;
     122              54 :     nBlockYSize = poDS->GetRasterYSize();
     123              54 : }
     124                 : 
     125                 : /************************************************************************/
     126                 : /*                             IReadBlock()                             */
     127                 : /************************************************************************/
     128                 : 
     129             160 : CPLErr BTRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     130                 :                                   void * pImage )
     131                 : 
     132                 : {
     133             160 :     int nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
     134                 :     int i;
     135                 : 
     136             160 :     CPLAssert( nBlockYOff == 0  );
     137                 : 
     138                 : /* -------------------------------------------------------------------- */
     139                 : /*      Seek to profile.                                                */
     140                 : /* -------------------------------------------------------------------- */
     141             160 :     if( VSIFSeekL( fpImage, 
     142                 :                    256 + nBlockXOff * nDataSize * nRasterYSize, 
     143                 :                    SEEK_SET ) != 0 )
     144                 :     {
     145                 :         CPLError( CE_Failure, CPLE_FileIO, 
     146               0 :                   ".bt Seek failed:%s", VSIStrerror( errno ) );
     147               0 :         return CE_Failure;
     148                 :     }
     149                 : 
     150                 : /* -------------------------------------------------------------------- */
     151                 : /*      Read the profile.                                               */
     152                 : /* -------------------------------------------------------------------- */
     153             160 :     if( VSIFReadL( pImage, nDataSize, nRasterYSize, fpImage ) != 
     154                 :         (size_t) nRasterYSize )
     155                 :     {
     156                 :         CPLError( CE_Failure, CPLE_FileIO, 
     157               0 :                   ".bt Read failed:%s", VSIStrerror( errno ) );
     158               0 :         return CE_Failure;
     159                 :     }
     160                 : 
     161                 : /* -------------------------------------------------------------------- */
     162                 : /*      Swap on MSB platforms.                                          */
     163                 : /* -------------------------------------------------------------------- */
     164                 : #ifdef CPL_MSB 
     165                 :     GDALSwapWords( pImage, nDataSize, nRasterYSize, nDataSize );
     166                 : #endif    
     167                 : 
     168                 : /* -------------------------------------------------------------------- */
     169                 : /*      Vertical flip, since GDAL expects values from top to bottom,    */
     170                 : /*      but in .bt they are bottom to top.                              */
     171                 : /* -------------------------------------------------------------------- */
     172            1760 :     for( i = 0; i < nRasterYSize / 2; i++ )
     173                 :     {
     174                 :         GByte abyWrk[8];
     175                 : 
     176            1600 :         memcpy( abyWrk, ((GByte *) pImage) + i * nDataSize, nDataSize );
     177                 :         memcpy( ((GByte *) pImage) + i * nDataSize, 
     178                 :                 ((GByte *) pImage) + (nRasterYSize - i - 1) * nDataSize, 
     179            1600 :                 nDataSize );
     180                 :         memcpy( ((GByte *) pImage) + (nRasterYSize - i - 1) * nDataSize, 
     181            1600 :                 abyWrk, nDataSize );
     182                 :     }
     183                 : 
     184             160 :     return CE_None;
     185                 : }
     186                 : 
     187                 : /************************************************************************/
     188                 : /*                            IWriteBlock()                             */
     189                 : /************************************************************************/
     190                 : 
     191             220 : CPLErr BTRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     192                 :                                   void * pImage )
     193                 : 
     194                 : {
     195             220 :     int nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
     196                 :     GByte *pabyWrkBlock;
     197                 :     int i;
     198                 : 
     199             220 :     CPLAssert( nBlockYOff == 0  );
     200                 : 
     201                 : /* -------------------------------------------------------------------- */
     202                 : /*      Seek to profile.                                                */
     203                 : /* -------------------------------------------------------------------- */
     204             220 :     if( VSIFSeekL( fpImage, 
     205                 :                    256 + nBlockXOff * nDataSize * nRasterYSize, 
     206                 :                    SEEK_SET ) != 0 )
     207                 :     {
     208                 :         CPLError( CE_Failure, CPLE_FileIO, 
     209               0 :                   ".bt Seek failed:%s", VSIStrerror( errno ) );
     210               0 :         return CE_Failure;
     211                 :     }
     212                 : 
     213                 : /* -------------------------------------------------------------------- */
     214                 : /*      Allocate working buffer.                                        */
     215                 : /* -------------------------------------------------------------------- */
     216             220 :     pabyWrkBlock = (GByte *) CPLMalloc(nDataSize * nRasterYSize);
     217                 : 
     218                 : /* -------------------------------------------------------------------- */
     219                 : /*      Vertical flip data into work buffer, since GDAL expects         */
     220                 : /*      values from top to bottom, but in .bt they are bottom to        */
     221                 : /*      top.                                                            */
     222                 : /* -------------------------------------------------------------------- */
     223            4020 :     for( i = 0; i < nRasterYSize; i++ )
     224                 :     {
     225                 :         memcpy( pabyWrkBlock + (nRasterYSize - i - 1) * nDataSize, 
     226            3800 :                 ((GByte *) pImage) + i * nDataSize, nDataSize );
     227                 :     }
     228                 : 
     229                 : /* -------------------------------------------------------------------- */
     230                 : /*      Swap on MSB platforms.                                          */
     231                 : /* -------------------------------------------------------------------- */
     232                 : #ifdef CPL_MSB 
     233                 :     GDALSwapWords( pabyWrkBlock, nDataSize, nRasterYSize, nDataSize );
     234                 : #endif    
     235                 : 
     236                 : /* -------------------------------------------------------------------- */
     237                 : /*      Read the profile.                                               */
     238                 : /* -------------------------------------------------------------------- */
     239             220 :     if( VSIFWriteL( pabyWrkBlock, nDataSize, nRasterYSize, fpImage ) != 
     240                 :         (size_t) nRasterYSize )
     241                 :     {
     242               0 :         CPLFree( pabyWrkBlock );
     243                 :         CPLError( CE_Failure, CPLE_FileIO, 
     244               0 :                   ".bt Write failed:%s", VSIStrerror( errno ) );
     245               0 :         return CE_Failure;
     246                 :     }
     247                 : 
     248             220 :     CPLFree( pabyWrkBlock );
     249                 : 
     250             220 :     return CE_None;
     251                 : }
     252                 : 
     253                 : 
     254              16 : double BTRasterBand::GetNoDataValue( int* pbSuccess /*= NULL */ )
     255                 : {
     256              16 :   if(pbSuccess != NULL)
     257              16 :     *pbSuccess = TRUE;
     258                 : 
     259              16 :   return -32768;
     260                 : }
     261                 : 
     262               0 : CPLErr BTRasterBand::SetNoDataValue( double )
     263                 : 
     264                 : {
     265               0 :     return CE_None;
     266                 : }
     267                 : 
     268                 : /************************************************************************/
     269                 : /*                            GetUnitType()                             */
     270                 : /************************************************************************/
     271                 : 
     272               0 : static bool approx_equals(float a, float b)
     273                 : {
     274               0 :     const float epsilon = (float)1e-5;
     275               0 :     return (fabs(a-b) <= epsilon);
     276                 : }
     277                 : 
     278               0 : const char* BTRasterBand::GetUnitType(void)
     279                 : {
     280               0 :     const BTDataset& ds = *(BTDataset*)poDS;
     281               0 :     float f = ds.m_fVscale;
     282               0 :     if(f == 1.0f)
     283               0 :         return "m";
     284               0 :     if(approx_equals(f, 0.3048f))
     285               0 :         return "ft";
     286               0 :     if(approx_equals(f, 1200.0f/3937.0f))
     287               0 :         return "sft";
     288                 : 
     289                 :     // todo: the BT spec allows for any value for
     290                 :     // ds.m_fVscale, so rigorous adherence would
     291                 :     // require testing for all possible units you
     292                 :     // may want to support, such as km, yards, miles, etc.
     293                 :     // But m/ft/sft seem to be the top three.
     294                 : 
     295               0 :     return "";
     296                 : } 
     297                 : 
     298                 : /************************************************************************/
     299                 : /*                            SetUnitType()                             */
     300                 : /************************************************************************/
     301                 : 
     302               0 : CPLErr BTRasterBand::SetUnitType(const char* psz)
     303                 : {
     304               0 :     BTDataset& ds = *(BTDataset*)poDS;
     305               0 :     if(EQUAL(psz, "m"))
     306               0 :         ds.m_fVscale = 1.0f;
     307               0 :     else if(EQUAL(psz, "ft"))
     308               0 :         ds.m_fVscale = 0.3048f;
     309               0 :     else if(EQUAL(psz, "sft"))
     310               0 :         ds.m_fVscale = 1200.0f / 3937.0f;
     311                 :     else
     312               0 :         return CE_Failure;
     313                 : 
     314                 : 
     315               0 :     float fScale = ds.m_fVscale;
     316                 : 
     317                 :     CPL_LSBPTR32(&fScale);
     318                 : 
     319                 :     // Update header's elevation scale field.
     320               0 :     memcpy(ds.abyHeader + 62, &fScale, sizeof(fScale));
     321                 : 
     322               0 :     ds.bHeaderModified = TRUE;
     323               0 :     return CE_None;
     324                 : } 
     325                 : 
     326                 : /************************************************************************/
     327                 : /* ==================================================================== */
     328                 : /*                              BTDataset                               */
     329                 : /* ==================================================================== */
     330                 : /************************************************************************/
     331                 : 
     332                 : /************************************************************************/
     333                 : /*                             BTDataset()                              */
     334                 : /************************************************************************/
     335                 : 
     336              54 : BTDataset::BTDataset()
     337                 : {
     338              54 :     fpImage = NULL;
     339              54 :     bGeoTransformValid = FALSE;
     340              54 :     adfGeoTransform[0] = 0.0;
     341              54 :     adfGeoTransform[1] = 1.0;
     342              54 :     adfGeoTransform[2] = 0.0;
     343              54 :     adfGeoTransform[3] = 0.0;
     344              54 :     adfGeoTransform[4] = 0.0;
     345              54 :     adfGeoTransform[5] = 1.0;
     346              54 :     pszProjection = NULL;
     347                 : 
     348              54 :     bHeaderModified = FALSE;
     349              54 : }
     350                 : 
     351                 : /************************************************************************/
     352                 : /*                             ~BTDataset()                             */
     353                 : /************************************************************************/
     354                 : 
     355              54 : BTDataset::~BTDataset()
     356                 : 
     357                 : {
     358              54 :     FlushCache();
     359              54 :     if( fpImage != NULL )
     360              54 :         VSIFCloseL( fpImage );
     361              54 :     CPLFree( pszProjection );
     362              54 : }
     363                 : 
     364                 : /************************************************************************/
     365                 : /*                             FlushCache()                             */
     366                 : /*                                                                      */
     367                 : /*      We override this to include flush out the header block.         */
     368                 : /************************************************************************/
     369                 : 
     370              54 : void BTDataset::FlushCache()
     371                 : 
     372                 : {
     373              54 :     GDALDataset::FlushCache();
     374                 : 
     375              54 :     if( !bHeaderModified )
     376              32 :         return;
     377                 : 
     378              22 :     bHeaderModified = FALSE;
     379                 : 
     380              22 :     VSIFSeekL( fpImage, 0, SEEK_SET );
     381              22 :     VSIFWriteL( abyHeader, 256, 1, fpImage );
     382                 : }
     383                 : 
     384                 : /************************************************************************/
     385                 : /*                          GetGeoTransform()                           */
     386                 : /************************************************************************/
     387                 : 
     388              14 : CPLErr BTDataset::GetGeoTransform( double * padfTransform )
     389                 : 
     390                 : {
     391              14 :     memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
     392                 : 
     393              14 :     if( bGeoTransformValid )
     394              14 :         return CE_None;
     395                 :     else
     396               0 :         return CE_Failure;
     397                 : }
     398                 : 
     399                 : /************************************************************************/
     400                 : /*                          SetGeoTransform()                           */
     401                 : /************************************************************************/
     402                 : 
     403              22 : CPLErr BTDataset::SetGeoTransform( double *padfTransform )
     404                 : 
     405                 : {
     406              22 :     CPLErr eErr = CE_None;
     407                 : 
     408              22 :     memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
     409              22 :     if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
     410                 :     {
     411                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     412               0 :                   ".bt format does not support rotational coefficients in geotransform, ignoring." );
     413               0 :         eErr = CE_Failure;
     414                 :     }
     415                 : 
     416                 : /* -------------------------------------------------------------------- */
     417                 : /*      Compute bounds, and update header info.                         */
     418                 : /* -------------------------------------------------------------------- */
     419                 :     double dfLeft, dfRight, dfTop, dfBottom;
     420                 : 
     421              22 :     dfLeft = adfGeoTransform[0];
     422              22 :     dfRight = dfLeft + adfGeoTransform[1] * nRasterXSize;
     423              22 :     dfTop = adfGeoTransform[3];
     424              22 :     dfBottom = dfTop + adfGeoTransform[5] * nRasterYSize;
     425                 : 
     426              22 :     memcpy( abyHeader + 28, &dfLeft, 8 );
     427              22 :     memcpy( abyHeader + 36, &dfRight, 8 );
     428              22 :     memcpy( abyHeader + 44, &dfBottom, 8 );
     429              22 :     memcpy( abyHeader + 52, &dfTop, 8 );
     430                 : 
     431                 :     CPL_LSBPTR64( abyHeader + 28 );
     432                 :     CPL_LSBPTR64( abyHeader + 36 );
     433                 :     CPL_LSBPTR64( abyHeader + 44 );
     434                 :     CPL_LSBPTR64( abyHeader + 52 );
     435                 :     
     436              22 :     bHeaderModified = TRUE;
     437                 : 
     438              22 :     return eErr;
     439                 : }
     440                 : 
     441                 : /************************************************************************/
     442                 : /*                          GetProjectionRef()                          */
     443                 : /************************************************************************/
     444                 : 
     445               8 : const char *BTDataset::GetProjectionRef()
     446                 : 
     447                 : {
     448               8 :     if( pszProjection == NULL )
     449               0 :         return "";
     450                 :     else
     451               8 :         return pszProjection;
     452                 : }
     453                 : 
     454                 : /************************************************************************/
     455                 : /*                           SetProjection()                            */
     456                 : /************************************************************************/
     457                 : 
     458              20 : CPLErr BTDataset::SetProjection( const char *pszNewProjection )
     459                 : 
     460                 : {
     461              20 :     CPLErr eErr = CE_None;
     462                 : 
     463              20 :     CPLFree( pszProjection );
     464              20 :     pszProjection = CPLStrdup( pszNewProjection );
     465                 : 
     466              20 :     bHeaderModified = TRUE;
     467                 : 
     468                 : /* -------------------------------------------------------------------- */
     469                 : /*      Parse projection.                                               */
     470                 : /* -------------------------------------------------------------------- */
     471              20 :     OGRSpatialReference oSRS( pszProjection );
     472                 :     GInt16  nShortTemp;
     473                 : 
     474                 : /* -------------------------------------------------------------------- */
     475                 : /*      Linear units.                                                   */
     476                 : /* -------------------------------------------------------------------- */
     477              20 :     if( oSRS.IsGeographic() )
     478              12 :         nShortTemp = 0;
     479                 :     else 
     480                 :     {
     481               8 :         double dfLinear = oSRS.GetLinearUnits();
     482                 : 
     483               8 :         if( ABS(dfLinear - 0.3048) < 0.0000001 )
     484               0 :             nShortTemp = 2;
     485               8 :         else if( ABS(dfLinear - atof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
     486               2 :             nShortTemp = 3;
     487                 :         else
     488               6 :             nShortTemp = 1;
     489                 :     }
     490                 : 
     491              20 :     nShortTemp = CPL_LSBWORD16( 1 );
     492              20 :     memcpy( abyHeader + 22, &nShortTemp, 2 );
     493                 :     
     494                 : /* -------------------------------------------------------------------- */
     495                 : /*      UTM Zone                                                        */
     496                 : /* -------------------------------------------------------------------- */
     497                 :     int bNorth;
     498                 : 
     499              20 :     nShortTemp = (GInt16) oSRS.GetUTMZone( &bNorth );
     500              20 :     if( bNorth )
     501              20 :         nShortTemp = -nShortTemp;
     502                 : 
     503              20 :     nShortTemp = CPL_LSBWORD16( nShortTemp );
     504              20 :     memcpy( abyHeader + 24, &nShortTemp, 2 );
     505                 :     
     506                 : /* -------------------------------------------------------------------- */
     507                 : /*      Datum                                                           */
     508                 : /* -------------------------------------------------------------------- */
     509              20 :     if( oSRS.GetAuthorityName( "GEOGCS|DATUM" ) != NULL
     510                 :         && EQUAL(oSRS.GetAuthorityName( "GEOGCS|DATUM" ),"EPSG") )
     511              14 :         nShortTemp = (GInt16) (atoi(oSRS.GetAuthorityCode( "GEOGCS|DATUM" )) + 2000);
     512                 :     else
     513               6 :         nShortTemp = -2;
     514              20 :     nShortTemp = CPL_LSBWORD16( nShortTemp ); /* datum unknown */
     515              20 :     memcpy( abyHeader + 26, &nShortTemp, 2 );
     516                 : 
     517                 : /* -------------------------------------------------------------------- */
     518                 : /*      Write out the projection to a .prj file.                        */
     519                 : /* -------------------------------------------------------------------- */
     520              20 :     const char  *pszPrjFile = CPLResetExtension( GetDescription(), "prj" );
     521                 :     VSILFILE * fp;
     522                 : 
     523              20 :     fp = VSIFOpenL( pszPrjFile, "wt" );
     524              20 :     if( fp != NULL )
     525                 :     {
     526              20 :         VSIFPrintfL( fp, "%s\n", pszProjection );
     527              20 :         VSIFCloseL( fp );
     528              20 :         abyHeader[60] = 1;
     529                 :     }
     530                 :     else
     531                 :     {
     532                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     533               0 :                   "Unable to write out .prj file." );
     534               0 :         eErr = CE_Failure;
     535                 :     }
     536                 : 
     537              20 :     return eErr;
     538                 : }
     539                 : 
     540                 : 
     541                 : /************************************************************************/
     542                 : /*                                Open()                                */
     543                 : /************************************************************************/
     544                 : 
     545           22646 : GDALDataset *BTDataset::Open( GDALOpenInfo * poOpenInfo )
     546                 : 
     547                 : {
     548                 : /* -------------------------------------------------------------------- */
     549                 : /*      Verify that this is some form of binterr file.                  */
     550                 : /* -------------------------------------------------------------------- */
     551           22646 :     if( poOpenInfo->nHeaderBytes < 256)
     552           21444 :         return NULL;
     553                 : 
     554            1202 :     if( strncmp( (const char *) poOpenInfo->pabyHeader, "binterr", 7 ) != 0 )
     555            1148 :         return NULL;
     556                 : 
     557                 : /* -------------------------------------------------------------------- */
     558                 : /*      Create the dataset.                                             */
     559                 : /* -------------------------------------------------------------------- */
     560                 :     BTDataset  *poDS;
     561                 : 
     562              54 :     poDS = new BTDataset();
     563                 :  
     564              54 :     memcpy( poDS->abyHeader, poOpenInfo->pabyHeader, 256 );
     565                 : 
     566                 : /* -------------------------------------------------------------------- */
     567                 : /*      Get the version.                                                */
     568                 : /* -------------------------------------------------------------------- */
     569                 :     char szVersion[4];
     570                 : 
     571              54 :     strncpy( szVersion, (char *) (poDS->abyHeader + 7), 3 );
     572              54 :     szVersion[3] = '\0';
     573              54 :     poDS->nVersionCode = (int) (atof(szVersion) * 10);
     574                 : 
     575                 : /* -------------------------------------------------------------------- */
     576                 : /*      Extract core header information, being careful about the        */
     577                 : /*      version.                                                        */
     578                 : /* -------------------------------------------------------------------- */
     579                 :     GInt32 nIntTemp;
     580                 :     GInt16 nDataSize;
     581                 :     GDALDataType eType;
     582                 : 
     583              54 :     memcpy( &nIntTemp, poDS->abyHeader + 10, 4 );
     584              54 :     poDS->nRasterXSize = CPL_LSBWORD32( nIntTemp );
     585                 :     
     586              54 :     memcpy( &nIntTemp, poDS->abyHeader + 14, 4 );
     587              54 :     poDS->nRasterYSize = CPL_LSBWORD32( nIntTemp );
     588                 : 
     589              54 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     590                 :     {
     591               0 :         delete poDS;
     592               0 :         return NULL;
     593                 :     }
     594                 : 
     595              54 :     memcpy( &nDataSize, poDS->abyHeader+18, 2 );
     596              54 :     nDataSize = CPL_LSBWORD16( nDataSize );
     597                 : 
     598              84 :     if( poDS->abyHeader[20] != 0 && nDataSize == 4 )
     599              30 :         eType = GDT_Float32;
     600              36 :     else if( poDS->abyHeader[20] == 0 && nDataSize == 4 )
     601              12 :         eType = GDT_Int32;
     602              24 :     else if( poDS->abyHeader[20] == 0 && nDataSize == 2 )
     603              12 :         eType = GDT_Int16;
     604                 :     else
     605                 :     {
     606                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     607                 :                   ".bt file data type unknown, got datasize=%d.", 
     608               0 :                   nDataSize );
     609               0 :         delete poDS;
     610               0 :         return NULL;
     611                 :     }
     612                 : 
     613                 :     /*
     614                 :         rcg, apr 7/06: read offset 62 for vert. units.
     615                 :         If zero, assume 1.0 as per spec.
     616                 : 
     617                 :     */
     618              54 :     memcpy( &poDS->m_fVscale, poDS->abyHeader + 62, 4 );
     619                 :     CPL_LSBPTR32(&poDS->m_fVscale);
     620              54 :     if(poDS->m_fVscale == 0.0f)
     621               0 :         poDS->m_fVscale = 1.0f; 
     622                 : 
     623                 : /* -------------------------------------------------------------------- */
     624                 : /*      Try to read a .prj file if it is indicated.                     */
     625                 : /* -------------------------------------------------------------------- */
     626              54 :     OGRSpatialReference oSRS;           
     627                 : 
     628              54 :     if( poDS->nVersionCode >= 12 && poDS->abyHeader[60] != 0 )
     629                 :     {
     630                 :         const char  *pszPrjFile = CPLResetExtension( poOpenInfo->pszFilename, 
     631              22 :                                                      "prj" );
     632                 :         VSILFILE *fp;
     633                 : 
     634              22 :         fp = VSIFOpenL( pszPrjFile, "rt" );
     635              22 :         if( fp != NULL )
     636                 :         {
     637                 :             char *pszBuffer, *pszBufPtr;
     638              22 :             int  nBufMax = 10000;
     639                 :             int nBytes;
     640                 : 
     641              22 :             pszBuffer = (char *) CPLMalloc(nBufMax);
     642              22 :             nBytes = VSIFReadL( pszBuffer, 1, nBufMax-1, fp );
     643              22 :             VSIFCloseL( fp );
     644                 : 
     645              22 :             pszBuffer[nBytes] = '\0';
     646                 : 
     647              22 :             pszBufPtr = pszBuffer;
     648              22 :             if( oSRS.importFromWkt( &pszBufPtr ) != OGRERR_NONE )
     649                 :             {
     650                 :                 CPLError( CE_Warning, CPLE_AppDefined, 
     651               0 :                           "Unable to parse .prj file, coordinate system missing." );
     652                 :             }
     653              22 :             CPLFree( pszBuffer );
     654                 :         }
     655                 :     }
     656                 : 
     657                 : /* -------------------------------------------------------------------- */
     658                 : /*      If we didn't find a .prj file, try to use internal info.        */
     659                 : /* -------------------------------------------------------------------- */
     660              54 :     if( oSRS.GetRoot() == NULL )
     661                 :     {
     662                 :         GInt16 nUTMZone, nDatum, nHUnits;
     663                 :         
     664              32 :         memcpy( &nUTMZone, poDS->abyHeader + 24, 2 );
     665              32 :         nUTMZone = CPL_LSBWORD16( nUTMZone );
     666                 :         
     667              32 :         memcpy( &nDatum, poDS->abyHeader + 26, 2 );
     668              32 :         nDatum = CPL_LSBWORD16( nDatum );
     669                 :         
     670              32 :         memcpy( &nHUnits, poDS->abyHeader + 22, 2 );
     671              32 :         nHUnits = CPL_LSBWORD16( nHUnits );
     672                 : 
     673              32 :         if( nUTMZone != 0 )
     674               0 :             oSRS.SetUTM( ABS(nUTMZone), nUTMZone > 0 );
     675              32 :         else if( nHUnits != 0 )
     676              32 :             oSRS.SetLocalCS( "Unknown" );
     677                 :         
     678              32 :         if( nHUnits == 1 )
     679              32 :             oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
     680               0 :         else if( nHUnits == 2 )
     681               0 :             oSRS.SetLinearUnits( SRS_UL_FOOT, atof(SRS_UL_FOOT_CONV) );
     682               0 :         else if( nHUnits == 3 )
     683               0 :             oSRS.SetLinearUnits( SRS_UL_US_FOOT, atof(SRS_UL_US_FOOT_CONV) );
     684                 : 
     685                 :         // Translate some of the more obvious old USGS datum codes 
     686              32 :         if( nDatum == 0 )
     687               0 :             nDatum = 6201;
     688              32 :         else if( nDatum == 1 )
     689               0 :             nDatum = 6209;
     690              32 :         else if( nDatum == 2 )
     691               0 :             nDatum = 6210;
     692              32 :         else if( nDatum == 3 )
     693               0 :             nDatum = 6202;
     694              32 :         else if( nDatum == 4 )
     695               0 :             nDatum = 6203;
     696              32 :         else if( nDatum == 4 )
     697               0 :             nDatum = 6203;
     698              32 :         else if( nDatum == 6 )
     699               0 :             nDatum = 6222;
     700              32 :         else if( nDatum == 7 )
     701               0 :             nDatum = 6230;
     702              32 :         else if( nDatum == 13 )
     703               0 :             nDatum = 6267;
     704              32 :         else if( nDatum == 14 )
     705               0 :             nDatum = 6269;
     706              32 :         else if( nDatum == 17 )
     707               0 :             nDatum = 6277;
     708              32 :         else if( nDatum == 19 )
     709               0 :             nDatum = 6284;
     710              32 :         else if( nDatum == 21 )
     711               0 :             nDatum = 6301;
     712              32 :         else if( nDatum == 22 )
     713               0 :             nDatum = 6322;
     714              32 :         else if( nDatum == 23 )
     715               0 :             nDatum = 6326;
     716                 : 
     717              32 :         if( !oSRS.IsLocal() )
     718                 :         {
     719               0 :             if( nDatum >= 6000 )
     720                 :             {
     721                 :                 char szName[32];
     722               0 :                 sprintf( szName, "EPSG:%d", nDatum-2000 );
     723               0 :                 oSRS.SetWellKnownGeogCS( szName );
     724                 :             }
     725                 :             else
     726               0 :                 oSRS.SetWellKnownGeogCS( "WGS84" );
     727                 :         }                
     728                 :     }
     729                 : 
     730                 : /* -------------------------------------------------------------------- */
     731                 : /*      Convert coordinate system back to WKT.                          */
     732                 : /* -------------------------------------------------------------------- */
     733              54 :     if( oSRS.GetRoot() != NULL )
     734              54 :         oSRS.exportToWkt( &poDS->pszProjection );
     735                 : 
     736                 : /* -------------------------------------------------------------------- */
     737                 : /*      Get georeferencing bounds.                                      */
     738                 : /* -------------------------------------------------------------------- */
     739              54 :     if( poDS->nVersionCode >= 11 )
     740                 :     {
     741                 :         double dfLeft, dfRight, dfTop, dfBottom;
     742                 : 
     743              54 :         memcpy( &dfLeft, poDS->abyHeader + 28, 8 );
     744                 :         CPL_LSBPTR64( &dfLeft );
     745                 :         
     746              54 :         memcpy( &dfRight, poDS->abyHeader + 36, 8 );
     747                 :         CPL_LSBPTR64( &dfRight );
     748                 :         
     749              54 :         memcpy( &dfBottom, poDS->abyHeader + 44, 8 );
     750                 :         CPL_LSBPTR64( &dfBottom );
     751                 :         
     752              54 :         memcpy( &dfTop, poDS->abyHeader + 52, 8 );
     753                 :         CPL_LSBPTR64( &dfTop );
     754                 : 
     755              54 :         poDS->adfGeoTransform[0] = dfLeft;
     756              54 :         poDS->adfGeoTransform[1] = (dfRight - dfLeft) / poDS->nRasterXSize;
     757              54 :         poDS->adfGeoTransform[2] = 0.0;
     758              54 :         poDS->adfGeoTransform[3] = dfTop;
     759              54 :         poDS->adfGeoTransform[4] = 0.0;
     760              54 :         poDS->adfGeoTransform[5] = (dfBottom - dfTop) / poDS->nRasterYSize;
     761                 :         
     762              54 :         poDS->bGeoTransformValid = TRUE;
     763                 :     }
     764                 :     
     765                 : /* -------------------------------------------------------------------- */
     766                 : /*      Re-open the file with the desired access.                       */
     767                 : /* -------------------------------------------------------------------- */
     768                 : 
     769              54 :     if( poOpenInfo->eAccess == GA_Update )
     770              24 :         poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
     771                 :     else
     772              30 :         poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     773                 : 
     774              54 :     if( poDS->fpImage == NULL )
     775                 :     {
     776                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     777                 :                   "Failed to re-open %s within BT driver.\n",
     778               0 :                   poOpenInfo->pszFilename );
     779               0 :         return NULL;
     780                 :     }
     781              54 :     poDS->eAccess = poOpenInfo->eAccess;
     782                 : 
     783                 : /* -------------------------------------------------------------------- */
     784                 : /*      Create band information objects                                 */
     785                 : /* -------------------------------------------------------------------- */
     786              54 :     poDS->SetBand( 1, new BTRasterBand( poDS, poDS->fpImage, eType ) );
     787                 : 
     788                 : #ifdef notdef
     789                 :     poDS->bGeoTransformValid = 
     790                 :         GDALReadWorldFile( poOpenInfo->pszFilename, ".wld", 
     791                 :                            poDS->adfGeoTransform );
     792                 : #endif
     793                 : 
     794                 : /* -------------------------------------------------------------------- */
     795                 : /*      Initialize any PAM information.                                 */
     796                 : /* -------------------------------------------------------------------- */
     797              54 :     poDS->SetDescription( poOpenInfo->pszFilename );
     798              54 :     poDS->TryLoadXML();
     799                 : 
     800                 : /* -------------------------------------------------------------------- */
     801                 : /*      Check for overviews.                                            */
     802                 : /* -------------------------------------------------------------------- */
     803              54 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     804                 : 
     805              54 :     return( poDS );
     806                 : }
     807                 : 
     808                 : /************************************************************************/
     809                 : /*                               Create()                               */
     810                 : /************************************************************************/
     811                 : 
     812              98 : GDALDataset *BTDataset::Create( const char * pszFilename,
     813                 :                                  int nXSize, int nYSize, int nBands,
     814                 :                                  GDALDataType eType,
     815                 :                                  char ** papszOptions )
     816                 : 
     817                 : {
     818                 : 
     819                 : /* -------------------------------------------------------------------- */
     820                 : /*      Verify input options.                                           */
     821                 : /* -------------------------------------------------------------------- */
     822              98 :     if( eType != GDT_Int16 && eType != GDT_Int32 && eType != GDT_Float32 )
     823                 :     {
     824                 :         CPLError( CE_Failure, CPLE_AppDefined,
     825                 :               "Attempt to create .bt dataset with an illegal\n"
     826                 :               "data type (%s), only Int16, Int32 and Float32 supported.\n",
     827              64 :               GDALGetDataTypeName(eType) );
     828                 : 
     829              64 :         return NULL;
     830                 :     }
     831                 : 
     832              34 :     if( nBands != 1 )
     833                 :     {
     834                 :         CPLError( CE_Failure, CPLE_AppDefined,
     835                 :                "Attempt to create .bt dataset with %d bands, only 1 supported",
     836               6 :                   nBands );
     837                 : 
     838               6 :         return NULL;
     839                 :     }
     840                 : 
     841                 : /* -------------------------------------------------------------------- */
     842                 : /*      Try to create the file.                                         */
     843                 : /* -------------------------------------------------------------------- */
     844                 :     VSILFILE        *fp;
     845                 : 
     846              28 :     fp = VSIFOpenL( pszFilename, "wb" );
     847                 : 
     848              28 :     if( fp == NULL )
     849                 :     {
     850                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     851                 :                   "Attempt to create file `%s' failed.\n",
     852               4 :                   pszFilename );
     853               4 :         return NULL;
     854                 :     }
     855                 : 
     856                 : /* -------------------------------------------------------------------- */
     857                 : /*      Setup base header.                                              */
     858                 : /* -------------------------------------------------------------------- */
     859                 :     unsigned char abyHeader[256];
     860                 :     GInt32 nTemp;
     861                 :     GInt16 nShortTemp;
     862                 : 
     863              24 :     memset( abyHeader, 0, 256 );
     864              24 :     memcpy( abyHeader, "binterr1.3", 10 );
     865                 :     
     866              24 :     nTemp = CPL_LSBWORD32( nXSize );
     867              24 :     memcpy( abyHeader+10, &nTemp, 4 );
     868                 :     
     869              24 :     nTemp = CPL_LSBWORD32( nYSize );
     870              24 :     memcpy( abyHeader+14, &nTemp, 4 );
     871                 : 
     872              24 :     nShortTemp = (GInt16) (CPL_LSBWORD16( GDALGetDataTypeSize( eType ) / 8 ));
     873              24 :     memcpy( abyHeader + 18, &nShortTemp, 2 );
     874                 :     
     875              24 :     if( eType == GDT_Float32 )
     876              12 :         abyHeader[20] = 1;
     877                 :     else
     878              12 :         abyHeader[20] = 0;
     879                 :     
     880              24 :     nShortTemp = CPL_LSBWORD16( 1 ); /* meters */
     881              24 :     memcpy( abyHeader + 22, &nShortTemp, 2 );
     882                 :     
     883              24 :     nShortTemp = CPL_LSBWORD16( 0 ); /* not utm */
     884              24 :     memcpy( abyHeader + 24, &nShortTemp, 2 );
     885                 :     
     886              24 :     nShortTemp = CPL_LSBWORD16( -2 ); /* datum unknown */
     887              24 :     memcpy( abyHeader + 26, &nShortTemp, 2 );
     888                 :     
     889                 : /* -------------------------------------------------------------------- */
     890                 : /*      Set dummy extents.                                              */
     891                 : /* -------------------------------------------------------------------- */
     892              24 :     double dfLeft=0, dfRight=nXSize, dfTop=nYSize, dfBottom=0;
     893                 : 
     894              24 :     memcpy( abyHeader + 28, &dfLeft, 8 );
     895              24 :     memcpy( abyHeader + 36, &dfRight, 8 );
     896              24 :     memcpy( abyHeader + 44, &dfBottom, 8 );
     897              24 :     memcpy( abyHeader + 52, &dfTop, 8 );
     898                 : 
     899                 :     CPL_LSBPTR64( abyHeader + 28 );
     900                 :     CPL_LSBPTR64( abyHeader + 36 );
     901                 :     CPL_LSBPTR64( abyHeader + 44 );
     902                 :     CPL_LSBPTR64( abyHeader + 52 );
     903                 :     
     904                 : /* -------------------------------------------------------------------- */
     905                 : /*      Set dummy scale.                                                */
     906                 : /* -------------------------------------------------------------------- */
     907              24 :     float fScale = 1.0;
     908                 : 
     909              24 :     memcpy( abyHeader + 62, &fScale, 4 );
     910                 :     CPL_LSBPTR32( abyHeader + 62 );
     911                 :     
     912                 : /* -------------------------------------------------------------------- */
     913                 : /*      Write to disk.                                                  */
     914                 : /* -------------------------------------------------------------------- */
     915              24 :     VSIFWriteL( (void *) abyHeader, 256, 1, fp );
     916              24 :     if( VSIFSeekL( fp, (GDALGetDataTypeSize(eType)/8) * nXSize * nYSize - 1, 
     917                 :                    SEEK_CUR ) != 0 
     918                 :         || VSIFWriteL( abyHeader+255, 1, 1, fp ) != 1 )
     919                 :     {
     920                 :         CPLError( CE_Failure, CPLE_FileIO, 
     921                 :                   "Failed to extent file to its full size, out of disk space?"
     922               0 :                   );
     923                 : 
     924               0 :         VSIFCloseL( fp );
     925               0 :         VSIUnlink( pszFilename );
     926               0 :         return NULL;
     927                 :     }
     928                 : 
     929              24 :     VSIFCloseL( fp );
     930                 : 
     931              24 :     return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
     932                 : }
     933                 : 
     934                 : /************************************************************************/
     935                 : /*                          GDALRegister_BT()                           */
     936                 : /************************************************************************/
     937                 : 
     938            1135 : void GDALRegister_BT()
     939                 : 
     940                 : {
     941                 :     GDALDriver  *poDriver;
     942                 : 
     943            1135 :     if( GDALGetDriverByName( "BT" ) == NULL )
     944                 :     {
     945            1093 :         poDriver = new GDALDriver();
     946                 : 
     947            1093 :         poDriver->SetDescription( "BT" );
     948                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
     949            1093 :                                    "VTP .bt (Binary Terrain) 1.3 Format" );
     950                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
     951            1093 :                                    "frmt_various.html#BT" );
     952            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "bt" );
     953                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
     954            1093 :                                    "Int16 Int32 Float32" );
     955            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     956                 : 
     957            1093 :         poDriver->pfnOpen = BTDataset::Open;
     958            1093 :         poDriver->pfnCreate = BTDataset::Create;
     959                 : 
     960            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     961                 :     }
     962            1135 : }

Generated by: LCOV version 1.7