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-12-26 Functions: 24 15 62.5 %

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

Generated by: LCOV version 1.7