LCOV - code coverage report
Current view: directory - frmts/bsb - bsbdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 244 120 49.2 %
Date: 2010-01-09 Functions: 21 11 52.4 %

       1                 : /******************************************************************************
       2                 :  * $Id: bsbdataset.cpp 18181 2009-12-05 01:07:47Z warmerdam $
       3                 :  *
       4                 :  * Project:  BSB Reader
       5                 :  * Purpose:  BSBDataset implementation for BSB format.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_pam.h"
      31                 : #include "bsb_read.h"
      32                 : #include "cpl_string.h"
      33                 : #include "ogr_spatialref.h"
      34                 : 
      35                 : CPL_CVSID("$Id: bsbdataset.cpp 18181 2009-12-05 01:07:47Z warmerdam $");
      36                 : 
      37                 : CPL_C_START
      38                 : void  GDALRegister_BSB(void);
      39                 : CPL_C_END
      40                 : 
      41                 : //Disabled as people may worry about the BSB patent
      42                 : //#define BSB_CREATE
      43                 : 
      44                 : /************************************************************************/
      45                 : /* ==================================================================== */
      46                 : /*        BSBDataset        */
      47                 : /* ==================================================================== */
      48                 : /************************************************************************/
      49                 : 
      50                 : class BSBRasterBand;
      51                 : 
      52                 : class BSBDataset : public GDALPamDataset
      53                 : {
      54                 :     int         nGCPCount;
      55                 :     GDAL_GCP    *pasGCPList;
      56                 :     CPLString   osGCPProjection;
      57                 : 
      58                 :     double      adfGeoTransform[6];
      59                 :     int         bGeoTransformSet;
      60                 : 
      61                 :     void        ScanForGCPs( bool isNos, const char *pszFilename );
      62                 :     void        ScanForGCPsNos( const char *pszFilename );
      63                 :     void        ScanForGCPsBSB();
      64                 :   public:
      65                 :                 BSBDataset();
      66                 :     ~BSBDataset();
      67                 :     
      68                 :     BSBInfo     *psInfo;
      69                 : 
      70                 :     static GDALDataset *Open( GDALOpenInfo * );
      71                 : 
      72                 :     virtual int    GetGCPCount();
      73                 :     virtual const char *GetGCPProjection();
      74                 :     virtual const GDAL_GCP *GetGCPs();
      75                 : 
      76                 :     CPLErr  GetGeoTransform( double * padfTransform );
      77                 :     const char *GetProjectionRef();
      78                 : };
      79                 : 
      80                 : /************************************************************************/
      81                 : /* ==================================================================== */
      82                 : /*                            BSBRasterBand                             */
      83                 : /* ==================================================================== */
      84                 : /************************************************************************/
      85                 : 
      86                 : class BSBRasterBand : public GDALPamRasterBand
      87              10 : {
      88                 :     GDALColorTable  oCT;
      89                 : 
      90                 :   public:
      91                 :         BSBRasterBand( BSBDataset * );
      92                 :     
      93                 :     virtual CPLErr IReadBlock( int, int, void * );
      94                 :     virtual GDALColorTable *GetColorTable();
      95                 :     virtual GDALColorInterp GetColorInterpretation();
      96                 : };
      97                 : 
      98                 : 
      99                 : /************************************************************************/
     100                 : /*                           BSBRasterBand()                            */
     101                 : /************************************************************************/
     102                 : 
     103               5 : BSBRasterBand::BSBRasterBand( BSBDataset *poDS )
     104                 : 
     105                 : {
     106               5 :     this->poDS = poDS;
     107               5 :     this->nBand = 1;
     108                 : 
     109               5 :     eDataType = GDT_Byte;
     110                 : 
     111               5 :     nBlockXSize = poDS->GetRasterXSize();
     112               5 :     nBlockYSize = 1;
     113                 : 
     114                 :     // Note that the first color table entry is dropped, everything is
     115                 :     // shifted down.
     116             640 :     for( int i = 0; i < poDS->psInfo->nPCTSize-1; i++ )
     117                 :     {
     118                 :         GDALColorEntry  oColor;
     119                 : 
     120             635 :         oColor.c1 = poDS->psInfo->pabyPCT[i*3+0+3];
     121             635 :         oColor.c2 = poDS->psInfo->pabyPCT[i*3+1+3];
     122             635 :         oColor.c3 = poDS->psInfo->pabyPCT[i*3+2+3];
     123             635 :         oColor.c4 = 255;
     124                 : 
     125             635 :         oCT.SetColorEntry( i, &oColor );
     126                 :     }
     127               5 : }
     128                 : 
     129                 : /************************************************************************/
     130                 : /*                             IReadBlock()                             */
     131                 : /************************************************************************/
     132                 : 
     133             250 : CPLErr BSBRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     134                 :                                       void * pImage )
     135                 : 
     136                 : {
     137             250 :     BSBDataset *poGDS = (BSBDataset *) poDS;
     138             250 :     GByte *pabyScanline = (GByte*) pImage;
     139                 : 
     140             250 :     if( BSBReadScanline( poGDS->psInfo, nBlockYOff, pabyScanline ) )
     141                 :     {
     142           12648 :         for( int i = 0; i < nBlockXSize; i++ )
     143           12400 :             pabyScanline[i] -= 1;
     144                 : 
     145             248 :         return CE_None;
     146                 :     }
     147                 :     else
     148               2 :         return CE_Failure;
     149                 : }
     150                 : 
     151                 : /************************************************************************/
     152                 : /*                           GetColorTable()                            */
     153                 : /************************************************************************/
     154                 : 
     155               0 : GDALColorTable *BSBRasterBand::GetColorTable()
     156                 : 
     157                 : {
     158               0 :     return &oCT;
     159                 : }
     160                 : 
     161                 : /************************************************************************/
     162                 : /*                       GetColorInterpretation()                       */
     163                 : /************************************************************************/
     164                 : 
     165               0 : GDALColorInterp BSBRasterBand::GetColorInterpretation()
     166                 : 
     167                 : {
     168               0 :     return GCI_PaletteIndex;
     169                 : }
     170                 : 
     171                 : /************************************************************************/
     172                 : /* ==================================================================== */
     173                 : /*        BSBDataset        */
     174                 : /* ==================================================================== */
     175                 : /************************************************************************/
     176                 : 
     177                 : /************************************************************************/
     178                 : /*                           BSBDataset()                               */
     179                 : /************************************************************************/
     180                 : 
     181               5 : BSBDataset::BSBDataset()
     182                 : 
     183                 : {
     184               5 :     psInfo = NULL;
     185                 : 
     186               5 :     bGeoTransformSet = FALSE;
     187                 : 
     188               5 :     nGCPCount = 0;
     189               5 :     pasGCPList = NULL;
     190               5 :     osGCPProjection = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",7030]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",6326]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",8901]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",9108]],AUTHORITY[\"EPSG\",4326]]";
     191                 : 
     192               5 :     adfGeoTransform[0] = 0.0;     /* X Origin (top left corner) */
     193               5 :     adfGeoTransform[1] = 1.0;     /* X Pixel size */
     194               5 :     adfGeoTransform[2] = 0.0;
     195               5 :     adfGeoTransform[3] = 0.0;     /* Y Origin (top left corner) */
     196               5 :     adfGeoTransform[4] = 0.0;     
     197               5 :     adfGeoTransform[5] = 1.0;     /* Y Pixel Size */
     198                 : 
     199               5 : }
     200                 : 
     201                 : /************************************************************************/
     202                 : /*                            ~BSBDataset()                             */
     203                 : /************************************************************************/
     204                 : 
     205              10 : BSBDataset::~BSBDataset()
     206                 : 
     207                 : {
     208               5 :     FlushCache();
     209                 : 
     210               5 :     GDALDeinitGCPs( nGCPCount, pasGCPList );
     211               5 :     CPLFree( pasGCPList );
     212                 : 
     213               5 :     if( psInfo != NULL )
     214               5 :         BSBClose( psInfo );
     215              10 : }
     216                 : 
     217                 : 
     218                 : /************************************************************************/
     219                 : /*                          GetGeoTransform()                           */
     220                 : /************************************************************************/
     221                 : 
     222               0 : CPLErr BSBDataset::GetGeoTransform( double * padfTransform )
     223                 : 
     224                 : {
     225               0 :     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
     226                 :     
     227               0 :     if( bGeoTransformSet )
     228               0 :         return CE_None;
     229                 :     else
     230               0 :         return CE_Failure;
     231                 : }
     232                 : 
     233                 : /************************************************************************/
     234                 : /*                          GetProjectionRef()                          */
     235                 : /************************************************************************/
     236                 : 
     237               0 : const char *BSBDataset::GetProjectionRef()
     238                 : 
     239                 : {
     240               0 :     if( bGeoTransformSet )
     241               0 :         return osGCPProjection;
     242                 :     else
     243               0 :         return "";
     244                 : }
     245                 : 
     246                 : /************************************************************************/
     247                 : /*                     GDALHeuristicDatelineWrap()                      */
     248                 : /************************************************************************/
     249                 : 
     250                 : static void 
     251               0 : GDALHeuristicDatelineWrap( int nPointCount, double *padfX )
     252                 : 
     253                 : {
     254                 :     int i;
     255                 :     /* Following inits are useless but keep GCC happy */
     256               0 :     double dfX_PM_Min = 0, dfX_PM_Max = 0, dfX_Dateline_Min = 0, dfX_Dateline_Max = 0;
     257                 :     int    bUsePMWrap;
     258                 : 
     259               0 :     if( nPointCount < 2 )
     260               0 :         return;
     261                 : 
     262                 : /* -------------------------------------------------------------------- */
     263                 : /*      Work out what the longitude range will be centering on the      */
     264                 : /*      prime meridian (-180 to 180) and centering on the dateline      */
     265                 : /*      (0 to 360).                                                     */
     266                 : /* -------------------------------------------------------------------- */
     267               0 :     for( i = 0; i < nPointCount; i++ )
     268                 :     {
     269                 :         double dfX_PM, dfX_Dateline;
     270                 : 
     271               0 :         dfX_PM = padfX[i];
     272               0 :         if( dfX_PM > 180 )
     273               0 :             dfX_PM -= 360.0;
     274                 : 
     275               0 :         dfX_Dateline = padfX[i];
     276               0 :         if( dfX_Dateline < 0 )
     277               0 :             dfX_Dateline += 360.0;
     278                 : 
     279               0 :         if( i == 0 )
     280                 :         {
     281               0 :             dfX_PM_Min = dfX_PM_Max = dfX_PM;
     282               0 :             dfX_Dateline_Min = dfX_Dateline_Max = dfX_Dateline;
     283                 :         }
     284                 :         else
     285                 :         {
     286               0 :             dfX_PM_Min = MIN(dfX_PM_Min,dfX_PM);
     287               0 :             dfX_PM_Max = MAX(dfX_PM_Max,dfX_PM);
     288               0 :             dfX_Dateline_Min = MIN(dfX_Dateline_Min,dfX_Dateline);
     289               0 :             dfX_Dateline_Max = MAX(dfX_Dateline_Max,dfX_Dateline);
     290                 :         }
     291                 :     }
     292                 : 
     293                 : /* -------------------------------------------------------------------- */
     294                 : /*      Do nothing if the range is always fairly small - no apparent    */
     295                 : /*      wrapping issues.                                                */
     296                 : /* -------------------------------------------------------------------- */
     297               0 :     if( (dfX_PM_Max - dfX_PM_Min) < 270.0
     298                 :         && (dfX_Dateline_Max - dfX_Dateline_Min) < 270.0 )
     299               0 :         return;
     300                 : 
     301                 : /* -------------------------------------------------------------------- */
     302                 : /*      Do nothing if both appproach have a wide range - best not to    */
     303                 : /*      fiddle if we aren't sure we are improving things.               */
     304                 : /* -------------------------------------------------------------------- */
     305               0 :     if( (dfX_PM_Max - dfX_PM_Min) > 270.0
     306                 :         && (dfX_Dateline_Max - dfX_Dateline_Min) > 270.0 )
     307               0 :         return;
     308                 : 
     309                 : /* -------------------------------------------------------------------- */
     310                 : /*      Pick which way to transform things.                             */
     311                 : /* -------------------------------------------------------------------- */
     312               0 :     if( (dfX_PM_Max - dfX_PM_Min) > 270.0
     313                 :         && (dfX_Dateline_Max - dfX_Dateline_Min) < 270.0 )
     314               0 :         bUsePMWrap = FALSE;
     315                 :     else
     316               0 :         bUsePMWrap = TRUE;
     317                 : 
     318                 : 
     319                 : /* -------------------------------------------------------------------- */
     320                 : /*      Apply rewrapping.                                               */
     321                 : /* -------------------------------------------------------------------- */
     322               0 :     for( i = 0; i < nPointCount; i++ )
     323                 :     {
     324               0 :         if( bUsePMWrap )
     325                 :         {
     326               0 :             if( padfX[i] > 180 )
     327               0 :                 padfX[i] -= 360.0;
     328                 :         }
     329                 :         else 
     330                 :         {
     331               0 :             if( padfX[i] < 0 )
     332               0 :                 padfX[i] += 360.0;
     333                 :         }
     334                 :     }
     335                 : }
     336                 : 
     337                 : /************************************************************************/
     338                 : /*                   GDALHeuristicDatelineWrapGCPs()                    */
     339                 : /************************************************************************/
     340                 : 
     341                 : static void
     342               0 : GDALHeuristicDatelineWrapGCPs( int nPointCount, GDAL_GCP *pasGCPList )
     343                 : {
     344               0 :     std::vector<double> oadfX;
     345                 :     int i;
     346                 : 
     347               0 :     oadfX.resize( nPointCount );
     348               0 :     for( i = 0; i < nPointCount; i++ )
     349               0 :         oadfX[i] = pasGCPList[i].dfGCPX;
     350                 : 
     351               0 :     GDALHeuristicDatelineWrap( nPointCount, &(oadfX[0]) );
     352                 : 
     353               0 :     for( i = 0; i < nPointCount; i++ )
     354               0 :         pasGCPList[i].dfGCPX = oadfX[i];
     355               0 : }
     356                 : 
     357                 : /************************************************************************/
     358                 : /*                            ScanForGCPs()                             */
     359                 : /************************************************************************/
     360                 : 
     361               5 : void BSBDataset::ScanForGCPs( bool isNos, const char *pszFilename )
     362                 : 
     363                 : {
     364                 : /* -------------------------------------------------------------------- */
     365                 : /*      Collect GCPs as appropriate to source.                          */
     366                 : /* -------------------------------------------------------------------- */
     367               5 :     nGCPCount = 0;
     368                 : 
     369               5 :     if ( isNos )
     370                 :     {
     371               0 :         ScanForGCPsNos(pszFilename);
     372                 :     } else {
     373               5 :         ScanForGCPsBSB();
     374                 :     }
     375                 : 
     376                 : /* -------------------------------------------------------------------- */
     377                 : /*      Apply heuristics to re-wrap GCPs to maintain continguity        */
     378                 : /*      over the international dateline.                                */
     379                 : /* -------------------------------------------------------------------- */
     380               5 :     if( nGCPCount > 1 )
     381               0 :         GDALHeuristicDatelineWrapGCPs( nGCPCount, pasGCPList );
     382                 : 
     383                 : /* -------------------------------------------------------------------- */
     384                 : /*      Can we derive a reasonable coordinate system definition for     */
     385                 : /*      this file?  For now we keep it simple, just handling            */
     386                 : /*      mercator. In the future we should consider others.              */
     387                 : /* -------------------------------------------------------------------- */
     388               5 :     CPLString osUnderlyingSRS;
     389                 :     int i;
     390                 : 
     391              15 :     for( i = 0; psInfo->papszHeader[i] != NULL; i++ )
     392                 :     {
     393              15 :         if( EQUALN(psInfo->papszHeader[i],"KNP/",4) )
     394                 :         {
     395               5 :             const char *pszPR = strstr(psInfo->papszHeader[i],"PR=");
     396                 : 
     397                 :             // Capture whole line as metadata so some apps can do more
     398                 :             // specific processing.
     399               5 :             SetMetadataItem( "BSB_KNP", psInfo->papszHeader[i] + 4 );
     400                 : 
     401               5 :             if( pszPR == NULL )
     402                 :             {
     403                 :                 /* no match */
     404                 :             }
     405               5 :             else if( EQUALN(pszPR,"PR=MERCATOR", 11) )
     406                 :             {
     407                 :                 // We somewhat arbitrarily select our first GCPX as our 
     408                 :                 // central meridian.  This is mostly helpful to ensure 
     409                 :                 // that regions crossing the dateline will be contiguous 
     410                 :                 // in mercator.
     411               5 :                 osUnderlyingSRS.Printf( "PROJCS[\"Global Mercator\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.01745329251994328]],PROJECTION[\"Mercator_2SP\"],PARAMETER[\"standard_parallel_1\",0],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",%d],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1]]", (int) pasGCPList[0].dfGCPX );
     412                 :             }
     413                 :             
     414               5 :             break;
     415                 :         }
     416                 :     }
     417                 : 
     418                 : /* -------------------------------------------------------------------- */
     419                 : /*      If we got an alternate underlying coordinate system, try        */
     420                 : /*      converting the GCPs to that coordinate system.                  */
     421                 : /* -------------------------------------------------------------------- */
     422               5 :     if( osUnderlyingSRS.length() > 0 )
     423                 :     {
     424               5 :         OGRSpatialReference oWGS84_SRS, oProjected_SRS;
     425                 :         OGRCoordinateTransformation *poCT;
     426                 :         
     427               5 :         oWGS84_SRS.SetWellKnownGeogCS( "WGS84" );
     428               5 :         oProjected_SRS.SetFromUserInput( osUnderlyingSRS );
     429                 :         
     430                 :         poCT = OGRCreateCoordinateTransformation( &oWGS84_SRS, 
     431               5 :                                                   &oProjected_SRS );
     432               5 :         if( poCT != NULL )
     433                 :         {
     434               5 :             for( i = 0; i < nGCPCount; i++ )
     435                 :             {
     436                 :                 poCT->Transform( 1, 
     437               0 :                                  &(pasGCPList[i].dfGCPX), 
     438               0 :                                  &(pasGCPList[i].dfGCPY), 
     439               0 :                                  &(pasGCPList[i].dfGCPZ) );
     440                 :             }
     441                 : 
     442               5 :             osGCPProjection = osUnderlyingSRS;
     443                 : 
     444               5 :             delete poCT;
     445                 :         }
     446                 :         else
     447               0 :             CPLErrorReset();
     448                 :     }
     449                 : 
     450                 : /* -------------------------------------------------------------------- */
     451                 : /*      Attempt to prepare a geotransform from the GCPs.                */
     452                 : /* -------------------------------------------------------------------- */
     453               5 :     if( GDALGCPsToGeoTransform( nGCPCount, pasGCPList, adfGeoTransform, 
     454                 :                                 FALSE ) )
     455                 :     {
     456               0 :         bGeoTransformSet = TRUE;
     457               5 :     }
     458               5 : }
     459                 : 
     460                 : /************************************************************************/
     461                 : /*                           ScanForGCPsNos()                           */
     462                 : /*                                                                      */
     463                 : /*      Nos files have an accompanying .geo file, that contains some    */
     464                 : /*      of the information normally contained in the header section     */
     465                 : /*      with BSB files. we try and open a file with the same name,      */
     466                 : /*      but a .geo extension, and look for lines like...                */
     467                 : /*      PointX=long lat line pixel    (using the same naming system     */
     468                 : /*      as BSB) Point1=-22.0000 64.250000 197 744                       */
     469                 : /************************************************************************/
     470                 : 
     471               0 : void BSBDataset::ScanForGCPsNos( const char *pszFilename )
     472                 : {
     473                 :     char **Tokens;
     474                 :     const char *geofile;
     475                 :     const char *extension;
     476               0 :     int fileGCPCount=0;
     477                 : 
     478               0 :     extension = CPLGetExtension(pszFilename);
     479                 : 
     480                 :     // pseudointelligently try and guess whether we want a .geo or a .GEO
     481               0 :     if (extension[1] == 'O')
     482                 :     {
     483               0 :         geofile = CPLResetExtension( pszFilename, "GEO");
     484                 :     } else {
     485               0 :         geofile = CPLResetExtension( pszFilename, "geo");
     486                 :     }
     487                 : 
     488               0 :     FILE *gfp = VSIFOpen( geofile, "r" );  // Text files
     489               0 :     if( gfp == NULL )
     490                 :     {
     491                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     492               0 :                   "Couldn't find a matching .GEO file: %s", geofile );
     493               0 :         return;
     494                 :     }
     495                 : 
     496               0 :     char *thisLine = (char *) CPLMalloc( 80 ); // FIXME
     497                 : 
     498                 :     // Count the GCPs (reference points) and seek the file pointer 'gfp' to the starting point
     499               0 :     while (fgets(thisLine, 80, gfp))
     500                 :     {
     501               0 :         if( EQUALN(thisLine, "Point", 5) )
     502               0 :             fileGCPCount++;
     503                 :     }
     504               0 :     VSIRewind( gfp );
     505                 : 
     506                 :     // Memory has not been allocated to fileGCPCount yet
     507               0 :     pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),fileGCPCount+1);
     508                 : 
     509               0 :     while (fgets(thisLine, 80, gfp))
     510                 :     {
     511               0 :         if( EQUALN(thisLine, "Point", 5) )
     512                 :         {
     513                 :             // got a point line, turn it into a gcp
     514               0 :             Tokens = CSLTokenizeStringComplex(thisLine, "= ", FALSE, FALSE);
     515               0 :             if (CSLCount(Tokens) >= 5)
     516                 :             {
     517               0 :                 GDALInitGCPs( 1, pasGCPList + nGCPCount );
     518               0 :                 pasGCPList[nGCPCount].dfGCPX = atof(Tokens[1]);
     519               0 :                 pasGCPList[nGCPCount].dfGCPY = atof(Tokens[2]);
     520               0 :                 pasGCPList[nGCPCount].dfGCPPixel = atof(Tokens[4]);
     521               0 :                 pasGCPList[nGCPCount].dfGCPLine = atof(Tokens[3]);
     522                 : 
     523               0 :                 CPLFree( pasGCPList[nGCPCount].pszId );
     524                 :                 char  szName[50];
     525               0 :                 sprintf( szName, "GCP_%d", nGCPCount+1 );
     526               0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup( szName );
     527                 : 
     528               0 :                 nGCPCount++;
     529                 :             }
     530               0 :             CSLDestroy(Tokens);
     531                 :         }
     532                 :     }
     533                 : 
     534               0 :     CPLFree(thisLine);
     535               0 :     VSIFClose(gfp);
     536                 : }
     537                 : 
     538                 : 
     539                 : /************************************************************************/
     540                 : /*                            ScanForGCPsBSB()                          */
     541                 : /************************************************************************/
     542                 : 
     543               5 : void BSBDataset::ScanForGCPsBSB()
     544                 : {
     545                 : /* -------------------------------------------------------------------- */
     546                 : /*      Collect standalone GCPs.  They look like:                       */
     547                 : /*                                                                      */
     548                 : /*      REF/1,115,2727,32.346666666667,-60.881666666667     */
     549                 : /*      REF/n,pixel,line,lat,long                                       */
     550                 : /* -------------------------------------------------------------------- */
     551               5 :     int fileGCPCount=0;
     552                 :     int i;
     553                 : 
     554                 :     // Count the GCPs (reference points) in psInfo->papszHeader
     555             655 :     for( i = 0; psInfo->papszHeader[i] != NULL; i++ )
     556             650 :         if( EQUALN(psInfo->papszHeader[i],"REF/",4) )
     557               0 :             fileGCPCount++;
     558                 : 
     559                 :     // Memory has not been allocated to fileGCPCount yet
     560               5 :     pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),fileGCPCount+1);
     561                 : 
     562             655 :     for( i = 0; psInfo->papszHeader[i] != NULL; i++ )
     563                 :     {
     564                 :         char  **papszTokens;
     565                 :         char  szName[50];
     566                 : 
     567             650 :         if( !EQUALN(psInfo->papszHeader[i],"REF/",4) )
     568             650 :             continue;
     569                 : 
     570                 :         papszTokens = 
     571               0 :             CSLTokenizeStringComplex( psInfo->papszHeader[i]+4, ",", 
     572               0 :                                       FALSE, FALSE );
     573                 : 
     574               0 :         if( CSLCount(papszTokens) > 4 )
     575                 :         {
     576               0 :             GDALInitGCPs( 1, pasGCPList + nGCPCount );
     577                 : 
     578               0 :             pasGCPList[nGCPCount].dfGCPX = atof(papszTokens[4]);
     579               0 :             pasGCPList[nGCPCount].dfGCPY = atof(papszTokens[3]);
     580               0 :             pasGCPList[nGCPCount].dfGCPPixel = atof(papszTokens[1]);
     581               0 :             pasGCPList[nGCPCount].dfGCPLine = atof(papszTokens[2]);
     582                 : 
     583               0 :             CPLFree( pasGCPList[nGCPCount].pszId );
     584               0 :             if( CSLCount(papszTokens) > 5 )
     585                 :             {
     586               0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
     587                 :             }
     588                 :             else
     589                 :             {
     590               0 :                 sprintf( szName, "GCP_%d", nGCPCount+1 );
     591               0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup( szName );
     592                 :             }
     593                 : 
     594               0 :             nGCPCount++;
     595                 :         }
     596               0 :         CSLDestroy( papszTokens );
     597                 :     }
     598               5 : }
     599                 : 
     600                 : /************************************************************************/
     601                 : /*                                Open()                                */
     602                 : /************************************************************************/
     603                 : 
     604            9629 : GDALDataset *BSBDataset::Open( GDALOpenInfo * poOpenInfo )
     605                 : 
     606                 : {
     607                 : /* -------------------------------------------------------------------- */
     608                 : /*      Check for BSB/ keyword.                                         */
     609                 : /* -------------------------------------------------------------------- */
     610                 :     int   i;
     611            9629 :     bool        isNos = false;
     612                 : 
     613            9629 :     if( poOpenInfo->nHeaderBytes < 1000 )
     614            8888 :         return NULL;
     615                 : 
     616          751596 :     for( i = 0; i < poOpenInfo->nHeaderBytes - 4; i++ )
     617                 :     {
     618          754407 :         if( poOpenInfo->pabyHeader[i+0] == 'B' 
     619            3532 :             && poOpenInfo->pabyHeader[i+1] == 'S' 
     620              10 :             && poOpenInfo->pabyHeader[i+2] == 'B' 
     621               5 :             && poOpenInfo->pabyHeader[i+3] == '/' )
     622               5 :             break;
     623          752879 :         if( poOpenInfo->pabyHeader[i+0] == 'N' 
     624            1954 :             && poOpenInfo->pabyHeader[i+1] == 'O' 
     625              63 :             && poOpenInfo->pabyHeader[i+2] == 'S' 
     626               7 :             && poOpenInfo->pabyHeader[i+3] == '/' )
     627                 :         {
     628               0 :             isNos = true;
     629               0 :             break;
     630                 :         }
     631          751575 :         if( poOpenInfo->pabyHeader[i+0] == 'W' 
     632             704 :             && poOpenInfo->pabyHeader[i+1] == 'X' 
     633              16 :             && poOpenInfo->pabyHeader[i+2] == '\\' 
     634               0 :             && poOpenInfo->pabyHeader[i+3] == '8' )
     635               0 :             break;
     636                 :     }
     637                 : 
     638             741 :     if( i == poOpenInfo->nHeaderBytes - 4 )
     639             736 :         return NULL;
     640                 : 
     641                 :     /* Additional test to avoid false positive. See #2881 */
     642               5 :     const char* pszRA = strstr((const char*)poOpenInfo->pabyHeader + i, "RA=");
     643               5 :     if (pszRA == NULL) /* This may be a NO1 file */
     644               0 :         pszRA = strstr((const char*)poOpenInfo->pabyHeader + i, "[JF");
     645               5 :     if (pszRA == NULL || pszRA - ((const char*)poOpenInfo->pabyHeader + i) > 100 )
     646               0 :         return NULL;
     647                 :         
     648               5 :     if( poOpenInfo->eAccess == GA_Update )
     649                 :     {
     650                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     651                 :                   "The BSB driver does not support update access to existing"
     652               0 :                   " datasets.\n" );
     653               0 :         return NULL;
     654                 :     }
     655                 : 
     656                 : /* -------------------------------------------------------------------- */
     657                 : /*      Create a corresponding GDALDataset.                             */
     658                 : /* -------------------------------------------------------------------- */
     659                 :     BSBDataset  *poDS;
     660                 : 
     661               5 :     poDS = new BSBDataset();
     662                 : 
     663                 : /* -------------------------------------------------------------------- */
     664                 : /*      Open the file.                                                  */
     665                 : /* -------------------------------------------------------------------- */
     666               5 :     poDS->psInfo = BSBOpen( poOpenInfo->pszFilename );
     667               5 :     if( poDS->psInfo == NULL )
     668                 :     {
     669               0 :         delete poDS;
     670               0 :         return NULL;
     671                 :     }
     672                 : 
     673               5 :     poDS->nRasterXSize = poDS->psInfo->nXSize;
     674               5 :     poDS->nRasterYSize = poDS->psInfo->nYSize;
     675                 : 
     676                 : /* -------------------------------------------------------------------- */
     677                 : /*      Create band information objects.                                */
     678                 : /* -------------------------------------------------------------------- */
     679               5 :     poDS->SetBand( 1, new BSBRasterBand( poDS ));
     680                 : 
     681               5 :     poDS->ScanForGCPs( isNos, poOpenInfo->pszFilename );
     682                 : 
     683                 : /* -------------------------------------------------------------------- */
     684                 : /*      Initialize any PAM information.                                 */
     685                 : /* -------------------------------------------------------------------- */
     686               5 :     poDS->SetDescription( poOpenInfo->pszFilename );
     687               5 :     poDS->TryLoadXML();
     688                 : 
     689               5 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     690                 : 
     691               5 :     return( poDS );
     692                 : }
     693                 : 
     694                 : /************************************************************************/
     695                 : /*                            GetGCPCount()                             */
     696                 : /************************************************************************/
     697                 : 
     698               0 : int BSBDataset::GetGCPCount()
     699                 : 
     700                 : {
     701               0 :     return nGCPCount;
     702                 : }
     703                 : 
     704                 : /************************************************************************/
     705                 : /*                          GetGCPProjection()                          */
     706                 : /************************************************************************/
     707                 : 
     708               0 : const char *BSBDataset::GetGCPProjection()
     709                 : 
     710                 : {
     711               0 :     return osGCPProjection;
     712                 : }
     713                 : 
     714                 : /************************************************************************/
     715                 : /*                               GetGCP()                               */
     716                 : /************************************************************************/
     717                 : 
     718               0 : const GDAL_GCP *BSBDataset::GetGCPs()
     719                 : 
     720                 : {
     721               0 :     return pasGCPList;
     722                 : }
     723                 : 
     724                 : #ifdef BSB_CREATE
     725                 : 
     726                 : /************************************************************************/
     727                 : /*                             BSBIsSRSOK()                             */
     728                 : /************************************************************************/
     729                 : 
     730                 : static int BSBIsSRSOK(const char *pszWKT)
     731                 : {
     732                 :     int bOK = FALSE;
     733                 :     OGRSpatialReference oSRS, oSRS_WGS84, oSRS_NAD83;
     734                 : 
     735                 :     if( pszWKT != NULL && pszWKT[0] != '\0' )
     736                 :     {
     737                 :         char* pszTmpWKT = (char*)pszWKT;
     738                 :         oSRS.importFromWkt( &pszTmpWKT );
     739                 : 
     740                 :         oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
     741                 :         oSRS_NAD83.SetWellKnownGeogCS( "NAD83" );
     742                 :         if ( (oSRS.IsSameGeogCS(&oSRS_WGS84) || oSRS.IsSameGeogCS(&oSRS_NAD83)) &&
     743                 :               oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0 )
     744                 :         {
     745                 :             bOK = TRUE;
     746                 :         }
     747                 :     }
     748                 : 
     749                 :     if (!bOK)
     750                 :     {
     751                 :         CPLError(CE_Warning, CPLE_NotSupported,
     752                 :                 "BSB only supports WGS84 or NAD83 geographic projections.\n");
     753                 :     }
     754                 : 
     755                 :     return bOK;
     756                 : }
     757                 : 
     758                 : /************************************************************************/
     759                 : /*                           BSBCreateCopy()                            */
     760                 : /************************************************************************/
     761                 : 
     762                 : static GDALDataset *
     763                 : BSBCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     764                 :                int bStrict, char ** papszOptions, 
     765                 :                GDALProgressFunc pfnProgress, void * pProgressData )
     766                 : 
     767                 : {
     768                 :     int  nBands = poSrcDS->GetRasterCount();
     769                 :     int  nXSize = poSrcDS->GetRasterXSize();
     770                 :     int  nYSize = poSrcDS->GetRasterYSize();
     771                 : 
     772                 : /* -------------------------------------------------------------------- */
     773                 : /*      Some some rudimentary checks                                    */
     774                 : /* -------------------------------------------------------------------- */
     775                 :     if( nBands != 1 )
     776                 :     {
     777                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     778                 :                   "BSB driver only supports one band images.\n" );
     779                 : 
     780                 :         return NULL;
     781                 :     }
     782                 : 
     783                 :     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
     784                 :         && bStrict )
     785                 :     {
     786                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     787                 :                   "BSB driver doesn't support data type %s. "
     788                 :                   "Only eight bit bands supported.\n", 
     789                 :                   GDALGetDataTypeName( 
     790                 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
     791                 : 
     792                 :         return NULL;
     793                 :     }
     794                 : 
     795                 : /* -------------------------------------------------------------------- */
     796                 : /*      Open the output file.                                           */
     797                 : /* -------------------------------------------------------------------- */
     798                 :     BSBInfo *psBSB;
     799                 : 
     800                 :     psBSB = BSBCreate( pszFilename, 0, 200, nXSize, nYSize );
     801                 :     if( psBSB == NULL )
     802                 :         return NULL;
     803                 : 
     804                 : /* -------------------------------------------------------------------- */
     805                 : /*      Prepare initial color table.colortable.                         */
     806                 : /* -------------------------------------------------------------------- */
     807                 :     GDALRasterBand  *poBand = poSrcDS->GetRasterBand(1);
     808                 :     int     iColor;
     809                 :     unsigned char       abyPCT[771];
     810                 :     int                 nPCTSize;
     811                 :     int                 anRemap[256];
     812                 : 
     813                 :     abyPCT[0] = 0;
     814                 :     abyPCT[1] = 0;
     815                 :     abyPCT[2] = 0;
     816                 : 
     817                 :     if( poBand->GetColorTable() == NULL )
     818                 :     {
     819                 :         /* map greyscale down to 63 grey levels. */
     820                 :         for( iColor = 0; iColor < 256; iColor++ )
     821                 :         {
     822                 :             int nOutValue = (int) (iColor / 4.1) + 1;
     823                 : 
     824                 :             anRemap[iColor] = nOutValue;
     825                 :             abyPCT[nOutValue*3 + 0] = (unsigned char) iColor;
     826                 :             abyPCT[nOutValue*3 + 1] = (unsigned char) iColor;
     827                 :             abyPCT[nOutValue*3 + 2] = (unsigned char) iColor;
     828                 :         }
     829                 :         nPCTSize = 64;
     830                 :     }
     831                 :     else
     832                 :     {
     833                 :         GDALColorTable  *poCT = poBand->GetColorTable();
     834                 :         int nColorTableSize = poCT->GetColorEntryCount();
     835                 :         if (nColorTableSize > 255)
     836                 :             nColorTableSize = 255;
     837                 : 
     838                 :         for( iColor = 0; iColor < nColorTableSize; iColor++ )
     839                 :         {
     840                 :             GDALColorEntry  sEntry;
     841                 : 
     842                 :             poCT->GetColorEntryAsRGB( iColor, &sEntry );
     843                 : 
     844                 :             anRemap[iColor] = iColor + 1;
     845                 :             abyPCT[(iColor+1)*3 + 0] = (unsigned char) sEntry.c1;
     846                 :             abyPCT[(iColor+1)*3 + 1] = (unsigned char) sEntry.c2;
     847                 :             abyPCT[(iColor+1)*3 + 2] = (unsigned char) sEntry.c3;
     848                 :         }
     849                 : 
     850                 :         nPCTSize = nColorTableSize + 1;
     851                 : 
     852                 :         // Add entries for pixel values which apparently will not occur.
     853                 :         for( iColor = nPCTSize; iColor < 256; iColor++ )
     854                 :             anRemap[iColor] = 1;
     855                 :     }
     856                 : 
     857                 : /* -------------------------------------------------------------------- */
     858                 : /*      Boil out all duplicate entries.                                 */
     859                 : /* -------------------------------------------------------------------- */
     860                 :     int  i;
     861                 : 
     862                 :     for( i = 1; i < nPCTSize-1; i++ )
     863                 :     {
     864                 :         int  j;
     865                 : 
     866                 :         for( j = i+1; j < nPCTSize; j++ )
     867                 :         {
     868                 :             if( abyPCT[i*3+0] == abyPCT[j*3+0] 
     869                 :                 && abyPCT[i*3+1] == abyPCT[j*3+1] 
     870                 :                 && abyPCT[i*3+2] == abyPCT[j*3+2] )
     871                 :             {
     872                 :                 int   k;
     873                 : 
     874                 :                 nPCTSize--;
     875                 :                 abyPCT[j*3+0] = abyPCT[nPCTSize*3+0];
     876                 :                 abyPCT[j*3+1] = abyPCT[nPCTSize*3+1];
     877                 :                 abyPCT[j*3+2] = abyPCT[nPCTSize*3+2];
     878                 : 
     879                 :                 for( k = 0; k < 256; k++ )
     880                 :                 {
     881                 :                     // merge matching entries.
     882                 :                     if( anRemap[k] == j )
     883                 :                         anRemap[k] = i;
     884                 : 
     885                 :                     // shift the last PCT entry into the new hole.
     886                 :                     if( anRemap[k] == nPCTSize )
     887                 :                         anRemap[k] = j;
     888                 :                 }
     889                 :             }
     890                 :         }
     891                 :     }
     892                 : 
     893                 : /* -------------------------------------------------------------------- */
     894                 : /*      Boil out all duplicate entries.                                 */
     895                 : /* -------------------------------------------------------------------- */
     896                 :     if( nPCTSize > 128 )
     897                 :     {
     898                 :         CPLError( CE_Warning, CPLE_AppDefined,
     899                 :                   "Having to merge color table entries to reduce %d real\n"
     900                 :                   "color table entries down to 127 values.", 
     901                 :                   nPCTSize );
     902                 :     }
     903                 : 
     904                 :     while( nPCTSize > 128 )
     905                 :     {
     906                 :         int nBestRange = 768;
     907                 :         int iBestMatch1=-1, iBestMatch2=-1;
     908                 : 
     909                 :         // Find the closest pair of color table entries.
     910                 : 
     911                 :         for( i = 1; i < nPCTSize-1; i++ )
     912                 :         {
     913                 :             int  j;
     914                 :             
     915                 :             for( j = i+1; j < nPCTSize; j++ )
     916                 :             {
     917                 :                 int nRange = ABS(abyPCT[i*3+0] - abyPCT[j*3+0])
     918                 :                     + ABS(abyPCT[i*3+1] - abyPCT[j*3+1])
     919                 :                     + ABS(abyPCT[i*3+2] - abyPCT[j*3+2]);
     920                 : 
     921                 :                 if( nRange < nBestRange )
     922                 :                 {
     923                 :                     iBestMatch1 = i;
     924                 :                     iBestMatch2 = j;
     925                 :                     nBestRange = nRange;
     926                 :                 }
     927                 :             }
     928                 :         }
     929                 : 
     930                 :         // Merge the second entry into the first. 
     931                 :         nPCTSize--;
     932                 :         abyPCT[iBestMatch2*3+0] = abyPCT[nPCTSize*3+0];
     933                 :         abyPCT[iBestMatch2*3+1] = abyPCT[nPCTSize*3+1];
     934                 :         abyPCT[iBestMatch2*3+2] = abyPCT[nPCTSize*3+2];
     935                 : 
     936                 :         for( i = 0; i < 256; i++ )
     937                 :         {
     938                 :             // merge matching entries.
     939                 :             if( anRemap[i] == iBestMatch2 )
     940                 :                 anRemap[i] = iBestMatch1;
     941                 :             
     942                 :             // shift the last PCT entry into the new hole.
     943                 :             if( anRemap[i] == nPCTSize )
     944                 :                 anRemap[i] = iBestMatch2;
     945                 :         }
     946                 :     }
     947                 : 
     948                 : /* -------------------------------------------------------------------- */
     949                 : /*      Write the PCT.                                                  */
     950                 : /* -------------------------------------------------------------------- */
     951                 :     if( !BSBWritePCT( psBSB, nPCTSize, abyPCT ) )
     952                 :     {
     953                 :         BSBClose( psBSB );
     954                 :         return NULL;
     955                 :     }
     956                 : 
     957                 : /* -------------------------------------------------------------------- */
     958                 : /*      Write the GCPs.                                                 */
     959                 : /* -------------------------------------------------------------------- */
     960                 :     double adfGeoTransform[6];
     961                 :     int nGCPCount = poSrcDS->GetGCPCount();
     962                 :     if (nGCPCount)
     963                 :     {
     964                 :         const char* pszGCPProjection = poSrcDS->GetGCPProjection();
     965                 :         if ( BSBIsSRSOK(pszGCPProjection) )
     966                 :         {
     967                 :             const GDAL_GCP * pasGCPList = poSrcDS->GetGCPs();
     968                 :             for( i = 0; i < nGCPCount; i++ )
     969                 :             {
     970                 :                 VSIFPrintfL( psBSB->fp, 
     971                 :                             "REF/%d,%f,%f,%f,%f\n", 
     972                 :                             i+1,
     973                 :                             pasGCPList[i].dfGCPPixel, pasGCPList[i].dfGCPLine,
     974                 :                             pasGCPList[i].dfGCPY, pasGCPList[i].dfGCPX);
     975                 :             }
     976                 :         }
     977                 :     }
     978                 :     else if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
     979                 :     {
     980                 :         const char* pszProjection = poSrcDS->GetProjectionRef();
     981                 :         if ( BSBIsSRSOK(pszProjection) )
     982                 :         {
     983                 :             VSIFPrintfL( psBSB->fp, 
     984                 :                         "REF/%d,%d,%d,%f,%f\n",
     985                 :                         1,
     986                 :                         0, 0,
     987                 :                         adfGeoTransform[3] + 0 * adfGeoTransform[4] + 0 * adfGeoTransform[5],
     988                 :                         adfGeoTransform[0] + 0 * adfGeoTransform[1] + 0 * adfGeoTransform[2]);
     989                 :             VSIFPrintfL( psBSB->fp, 
     990                 :                         "REF/%d,%d,%d,%f,%f\n",
     991                 :                         2,
     992                 :                         nXSize, 0,
     993                 :                         adfGeoTransform[3] + nXSize * adfGeoTransform[4] + 0 * adfGeoTransform[5],
     994                 :                         adfGeoTransform[0] + nXSize * adfGeoTransform[1] + 0 * adfGeoTransform[2]);
     995                 :             VSIFPrintfL( psBSB->fp, 
     996                 :                         "REF/%d,%d,%d,%f,%f\n",
     997                 :                         3,
     998                 :                         nXSize, nYSize,
     999                 :                         adfGeoTransform[3] + nXSize * adfGeoTransform[4] + nYSize * adfGeoTransform[5],
    1000                 :                         adfGeoTransform[0] + nXSize * adfGeoTransform[1] + nYSize * adfGeoTransform[2]);
    1001                 :             VSIFPrintfL( psBSB->fp, 
    1002                 :                         "REF/%d,%d,%d,%f,%f\n",
    1003                 :                         4,
    1004                 :                         0, nYSize,
    1005                 :                         adfGeoTransform[3] + 0 * adfGeoTransform[4] + nYSize * adfGeoTransform[5],
    1006                 :                         adfGeoTransform[0] + 0 * adfGeoTransform[1] + nYSize * adfGeoTransform[2]);
    1007                 :         }
    1008                 :     }
    1009                 : 
    1010                 : /* -------------------------------------------------------------------- */
    1011                 : /*      Loop over image, copying image data.                            */
    1012                 : /* -------------------------------------------------------------------- */
    1013                 :     GByte   *pabyScanline;
    1014                 :     CPLErr      eErr = CE_None;
    1015                 : 
    1016                 :     pabyScanline = (GByte *) CPLMalloc( nXSize );
    1017                 : 
    1018                 :     for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )
    1019                 :     {
    1020                 :         eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    1021                 :                                  pabyScanline, nXSize, 1, GDT_Byte,
    1022                 :                                  nBands, nBands * nXSize );
    1023                 :         if( eErr == CE_None )
    1024                 :         {
    1025                 :             for( i = 0; i < nXSize; i++ )
    1026                 :                 pabyScanline[i] = (GByte) anRemap[pabyScanline[i]];
    1027                 : 
    1028                 :             if( !BSBWriteScanline( psBSB, pabyScanline ) )
    1029                 :                 eErr = CE_Failure;
    1030                 :         }
    1031                 :     }
    1032                 : 
    1033                 :     CPLFree( pabyScanline );
    1034                 : 
    1035                 : /* -------------------------------------------------------------------- */
    1036                 : /*      cleanup                                                         */
    1037                 : /* -------------------------------------------------------------------- */
    1038                 :     BSBClose( psBSB );
    1039                 : 
    1040                 :     if( eErr != CE_None )
    1041                 :     {
    1042                 :         VSIUnlink( pszFilename );
    1043                 :         return NULL;
    1044                 :     }
    1045                 :     else
    1046                 :         return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
    1047                 : }
    1048                 : #endif
    1049                 : 
    1050                 : /************************************************************************/
    1051                 : /*                        GDALRegister_BSB()                            */
    1052                 : /************************************************************************/
    1053                 : 
    1054             338 : void GDALRegister_BSB()
    1055                 : 
    1056                 : {
    1057                 :     GDALDriver  *poDriver;
    1058                 : 
    1059             338 :     if( GDALGetDriverByName( "BSB" ) == NULL )
    1060                 :     {
    1061             336 :         poDriver = new GDALDriver();
    1062                 :         
    1063             336 :         poDriver->SetDescription( "BSB" );
    1064                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1065             336 :                                    "Maptech BSB Nautical Charts" );
    1066                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1067             336 :                                    "frmt_various.html#BSB" );
    1068                 : #ifdef BSB_CREATE
    1069                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
    1070                 : #endif
    1071             336 :         poDriver->pfnOpen = BSBDataset::Open;
    1072                 : #ifdef BSB_CREATE
    1073                 :         poDriver->pfnCreateCopy = BSBCreateCopy;
    1074                 : #endif
    1075                 : 
    1076             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1077                 :     }
    1078             338 : }

Generated by: LCOV version 1.7