LCOV - code coverage report
Current view: directory - frmts/bsb - bsbdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 294 145 49.3 %
Date: 2012-12-26 Functions: 26 11 42.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: bsbdataset.cpp 25340 2012-12-21 20:30:21Z rouault $
       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 25340 2012-12-21 20:30:21Z rouault $");
      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                 : 
      65                 :     static int IdentifyInternal( GDALOpenInfo *, bool & isNosOut );
      66                 : 
      67                 :   public:
      68                 :                 BSBDataset();
      69                 :     ~BSBDataset();
      70                 :     
      71                 :     BSBInfo     *psInfo;
      72                 : 
      73                 :     static GDALDataset *Open( GDALOpenInfo * );
      74                 :     static int Identify( GDALOpenInfo * );
      75                 : 
      76                 :     virtual int    GetGCPCount();
      77                 :     virtual const char *GetGCPProjection();
      78                 :     virtual const GDAL_GCP *GetGCPs();
      79                 : 
      80                 :     CPLErr  GetGeoTransform( double * padfTransform );
      81                 :     const char *GetProjectionRef();
      82                 : };
      83                 : 
      84                 : /************************************************************************/
      85                 : /* ==================================================================== */
      86                 : /*                            BSBRasterBand                             */
      87                 : /* ==================================================================== */
      88                 : /************************************************************************/
      89                 : 
      90                 : class BSBRasterBand : public GDALPamRasterBand
      91               5 : {
      92                 :     GDALColorTable  oCT;
      93                 : 
      94                 :   public:
      95                 :         BSBRasterBand( BSBDataset * );
      96                 :     
      97                 :     virtual CPLErr IReadBlock( int, int, void * );
      98                 :     virtual GDALColorTable *GetColorTable();
      99                 :     virtual GDALColorInterp GetColorInterpretation();
     100                 : };
     101                 : 
     102                 : 
     103                 : /************************************************************************/
     104                 : /*                           BSBRasterBand()                            */
     105                 : /************************************************************************/
     106                 : 
     107               5 : BSBRasterBand::BSBRasterBand( BSBDataset *poDS )
     108                 : 
     109                 : {
     110               5 :     this->poDS = poDS;
     111               5 :     this->nBand = 1;
     112                 : 
     113               5 :     eDataType = GDT_Byte;
     114                 : 
     115               5 :     nBlockXSize = poDS->GetRasterXSize();
     116               5 :     nBlockYSize = 1;
     117                 : 
     118                 :     // Note that the first color table entry is dropped, everything is
     119                 :     // shifted down.
     120             640 :     for( int i = 0; i < poDS->psInfo->nPCTSize-1; i++ )
     121                 :     {
     122                 :         GDALColorEntry  oColor;
     123                 : 
     124             635 :         oColor.c1 = poDS->psInfo->pabyPCT[i*3+0+3];
     125             635 :         oColor.c2 = poDS->psInfo->pabyPCT[i*3+1+3];
     126             635 :         oColor.c3 = poDS->psInfo->pabyPCT[i*3+2+3];
     127             635 :         oColor.c4 = 255;
     128                 : 
     129             635 :         oCT.SetColorEntry( i, &oColor );
     130                 :     }
     131               5 : }
     132                 : 
     133                 : /************************************************************************/
     134                 : /*                             IReadBlock()                             */
     135                 : /************************************************************************/
     136                 : 
     137             250 : CPLErr BSBRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     138                 :                                       void * pImage )
     139                 : 
     140                 : {
     141             250 :     BSBDataset *poGDS = (BSBDataset *) poDS;
     142             250 :     GByte *pabyScanline = (GByte*) pImage;
     143                 : 
     144             250 :     if( BSBReadScanline( poGDS->psInfo, nBlockYOff, pabyScanline ) )
     145                 :     {
     146           12648 :         for( int i = 0; i < nBlockXSize; i++ )
     147                 :         {
     148                 :             /* The indices start at 1, except in case of some charts */
     149                 :             /* where there are missing values, which are filled to 0 */
     150                 :             /* by BSBReadScanline */
     151           12400 :             if (pabyScanline[i] > 0)
     152           12400 :                 pabyScanline[i] -= 1;
     153                 :         }
     154                 : 
     155             248 :         return CE_None;
     156                 :     }
     157                 :     else
     158               2 :         return CE_Failure;
     159                 : }
     160                 : 
     161                 : /************************************************************************/
     162                 : /*                           GetColorTable()                            */
     163                 : /************************************************************************/
     164                 : 
     165               0 : GDALColorTable *BSBRasterBand::GetColorTable()
     166                 : 
     167                 : {
     168               0 :     return &oCT;
     169                 : }
     170                 : 
     171                 : /************************************************************************/
     172                 : /*                       GetColorInterpretation()                       */
     173                 : /************************************************************************/
     174                 : 
     175               0 : GDALColorInterp BSBRasterBand::GetColorInterpretation()
     176                 : 
     177                 : {
     178               0 :     return GCI_PaletteIndex;
     179                 : }
     180                 : 
     181                 : /************************************************************************/
     182                 : /* ==================================================================== */
     183                 : /*        BSBDataset        */
     184                 : /* ==================================================================== */
     185                 : /************************************************************************/
     186                 : 
     187                 : /************************************************************************/
     188                 : /*                           BSBDataset()                               */
     189                 : /************************************************************************/
     190                 : 
     191               5 : BSBDataset::BSBDataset()
     192                 : 
     193                 : {
     194               5 :     psInfo = NULL;
     195                 : 
     196               5 :     bGeoTransformSet = FALSE;
     197                 : 
     198               5 :     nGCPCount = 0;
     199               5 :     pasGCPList = NULL;
     200               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]]";
     201                 : 
     202               5 :     adfGeoTransform[0] = 0.0;     /* X Origin (top left corner) */
     203               5 :     adfGeoTransform[1] = 1.0;     /* X Pixel size */
     204               5 :     adfGeoTransform[2] = 0.0;
     205               5 :     adfGeoTransform[3] = 0.0;     /* Y Origin (top left corner) */
     206               5 :     adfGeoTransform[4] = 0.0;     
     207               5 :     adfGeoTransform[5] = 1.0;     /* Y Pixel Size */
     208                 : 
     209               5 : }
     210                 : 
     211                 : /************************************************************************/
     212                 : /*                            ~BSBDataset()                             */
     213                 : /************************************************************************/
     214                 : 
     215               5 : BSBDataset::~BSBDataset()
     216                 : 
     217                 : {
     218               5 :     FlushCache();
     219                 : 
     220               5 :     GDALDeinitGCPs( nGCPCount, pasGCPList );
     221               5 :     CPLFree( pasGCPList );
     222                 : 
     223               5 :     if( psInfo != NULL )
     224               5 :         BSBClose( psInfo );
     225               5 : }
     226                 : 
     227                 : 
     228                 : /************************************************************************/
     229                 : /*                          GetGeoTransform()                           */
     230                 : /************************************************************************/
     231                 : 
     232               0 : CPLErr BSBDataset::GetGeoTransform( double * padfTransform )
     233                 : 
     234                 : {
     235               0 :     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
     236                 :     
     237               0 :     if( bGeoTransformSet )
     238               0 :         return CE_None;
     239                 :     else
     240               0 :         return CE_Failure;
     241                 : }
     242                 : 
     243                 : /************************************************************************/
     244                 : /*                          GetProjectionRef()                          */
     245                 : /************************************************************************/
     246                 : 
     247               0 : const char *BSBDataset::GetProjectionRef()
     248                 : 
     249                 : {
     250               0 :     if( bGeoTransformSet )
     251               0 :         return osGCPProjection;
     252                 :     else
     253               0 :         return "";
     254                 : }
     255                 : 
     256                 : /************************************************************************/
     257                 : /*                     GDALHeuristicDatelineWrap()                      */
     258                 : /************************************************************************/
     259                 : 
     260                 : static void 
     261               0 : GDALHeuristicDatelineWrap( int nPointCount, double *padfX )
     262                 : 
     263                 : {
     264                 :     int i;
     265                 :     /* Following inits are useless but keep GCC happy */
     266               0 :     double dfX_PM_Min = 0, dfX_PM_Max = 0, dfX_Dateline_Min = 0, dfX_Dateline_Max = 0;
     267                 :     int    bUsePMWrap;
     268                 : 
     269               0 :     if( nPointCount < 2 )
     270               0 :         return;
     271                 : 
     272                 : /* -------------------------------------------------------------------- */
     273                 : /*      Work out what the longitude range will be centering on the      */
     274                 : /*      prime meridian (-180 to 180) and centering on the dateline      */
     275                 : /*      (0 to 360).                                                     */
     276                 : /* -------------------------------------------------------------------- */
     277               0 :     for( i = 0; i < nPointCount; i++ )
     278                 :     {
     279                 :         double dfX_PM, dfX_Dateline;
     280                 : 
     281               0 :         dfX_PM = padfX[i];
     282               0 :         if( dfX_PM > 180 )
     283               0 :             dfX_PM -= 360.0;
     284                 : 
     285               0 :         dfX_Dateline = padfX[i];
     286               0 :         if( dfX_Dateline < 0 )
     287               0 :             dfX_Dateline += 360.0;
     288                 : 
     289               0 :         if( i == 0 )
     290                 :         {
     291               0 :             dfX_PM_Min = dfX_PM_Max = dfX_PM;
     292               0 :             dfX_Dateline_Min = dfX_Dateline_Max = dfX_Dateline;
     293                 :         }
     294                 :         else
     295                 :         {
     296               0 :             dfX_PM_Min = MIN(dfX_PM_Min,dfX_PM);
     297               0 :             dfX_PM_Max = MAX(dfX_PM_Max,dfX_PM);
     298               0 :             dfX_Dateline_Min = MIN(dfX_Dateline_Min,dfX_Dateline);
     299               0 :             dfX_Dateline_Max = MAX(dfX_Dateline_Max,dfX_Dateline);
     300                 :         }
     301                 :     }
     302                 : 
     303                 : /* -------------------------------------------------------------------- */
     304                 : /*      Do nothing if the range is always fairly small - no apparent    */
     305                 : /*      wrapping issues.                                                */
     306                 : /* -------------------------------------------------------------------- */
     307               0 :     if( (dfX_PM_Max - dfX_PM_Min) < 270.0
     308                 :         && (dfX_Dateline_Max - dfX_Dateline_Min) < 270.0 )
     309               0 :         return;
     310                 : 
     311                 : /* -------------------------------------------------------------------- */
     312                 : /*      Do nothing if both appproach have a wide range - best not to    */
     313                 : /*      fiddle if we aren't sure we are improving things.               */
     314                 : /* -------------------------------------------------------------------- */
     315               0 :     if( (dfX_PM_Max - dfX_PM_Min) > 270.0
     316                 :         && (dfX_Dateline_Max - dfX_Dateline_Min) > 270.0 )
     317               0 :         return;
     318                 : 
     319                 : /* -------------------------------------------------------------------- */
     320                 : /*      Pick which way to transform things.                             */
     321                 : /* -------------------------------------------------------------------- */
     322               0 :     if( (dfX_PM_Max - dfX_PM_Min) > 270.0
     323                 :         && (dfX_Dateline_Max - dfX_Dateline_Min) < 270.0 )
     324               0 :         bUsePMWrap = FALSE;
     325                 :     else
     326               0 :         bUsePMWrap = TRUE;
     327                 : 
     328                 : 
     329                 : /* -------------------------------------------------------------------- */
     330                 : /*      Apply rewrapping.                                               */
     331                 : /* -------------------------------------------------------------------- */
     332               0 :     for( i = 0; i < nPointCount; i++ )
     333                 :     {
     334               0 :         if( bUsePMWrap )
     335                 :         {
     336               0 :             if( padfX[i] > 180 )
     337               0 :                 padfX[i] -= 360.0;
     338                 :         }
     339                 :         else 
     340                 :         {
     341               0 :             if( padfX[i] < 0 )
     342               0 :                 padfX[i] += 360.0;
     343                 :         }
     344                 :     }
     345                 : }
     346                 : 
     347                 : /************************************************************************/
     348                 : /*                   GDALHeuristicDatelineWrapGCPs()                    */
     349                 : /************************************************************************/
     350                 : 
     351                 : static void
     352               0 : GDALHeuristicDatelineWrapGCPs( int nPointCount, GDAL_GCP *pasGCPList )
     353                 : {
     354               0 :     std::vector<double> oadfX;
     355                 :     int i;
     356                 : 
     357               0 :     oadfX.resize( nPointCount );
     358               0 :     for( i = 0; i < nPointCount; i++ )
     359               0 :         oadfX[i] = pasGCPList[i].dfGCPX;
     360                 : 
     361               0 :     GDALHeuristicDatelineWrap( nPointCount, &(oadfX[0]) );
     362                 : 
     363               0 :     for( i = 0; i < nPointCount; i++ )
     364               0 :         pasGCPList[i].dfGCPX = oadfX[i];
     365               0 : }
     366                 : 
     367                 : /************************************************************************/
     368                 : /*                            ScanForGCPs()                             */
     369                 : /************************************************************************/
     370                 : 
     371               5 : void BSBDataset::ScanForGCPs( bool isNos, const char *pszFilename )
     372                 : 
     373                 : {
     374                 : /* -------------------------------------------------------------------- */
     375                 : /*      Collect GCPs as appropriate to source.                          */
     376                 : /* -------------------------------------------------------------------- */
     377               5 :     nGCPCount = 0;
     378                 : 
     379               5 :     if ( isNos )
     380                 :     {
     381               0 :         ScanForGCPsNos(pszFilename);
     382                 :     } else {
     383               5 :         ScanForGCPsBSB();
     384                 :     }
     385                 : 
     386                 : /* -------------------------------------------------------------------- */
     387                 : /*      Apply heuristics to re-wrap GCPs to maintain continguity        */
     388                 : /*      over the international dateline.                                */
     389                 : /* -------------------------------------------------------------------- */
     390               5 :     if( nGCPCount > 1 )
     391               0 :         GDALHeuristicDatelineWrapGCPs( nGCPCount, pasGCPList );
     392                 : 
     393                 : /* -------------------------------------------------------------------- */
     394                 : /*      Collect coordinate system related parameters from header.       */
     395                 : /* -------------------------------------------------------------------- */
     396                 :     int i;
     397               5 :     const char *pszKNP=NULL, *pszKNQ=NULL;
     398                 : 
     399             655 :     for( i = 0; psInfo->papszHeader[i] != NULL; i++ )
     400                 :     {
     401             650 :         if( EQUALN(psInfo->papszHeader[i],"KNP/",4) )
     402                 :         {
     403               5 :             pszKNP = psInfo->papszHeader[i];
     404               5 :             SetMetadataItem( "BSB_KNP", pszKNP + 4 );
     405                 :         }
     406             650 :         if( EQUALN(psInfo->papszHeader[i],"KNQ/",4) )
     407                 :         {
     408               0 :             pszKNQ = psInfo->papszHeader[i]; 
     409               0 :             SetMetadataItem( "BSB_KNQ", pszKNQ + 4 );
     410                 :         }
     411                 :     }
     412                 : 
     413                 :     
     414                 : /* -------------------------------------------------------------------- */
     415                 : /*      Can we derive a reasonable coordinate system definition for     */
     416                 : /*      this file?  For now we keep it simple, just handling            */
     417                 : /*      mercator. In the future we should consider others.              */
     418                 : /* -------------------------------------------------------------------- */
     419               5 :     CPLString osUnderlyingSRS;
     420               5 :     if( pszKNP != NULL )
     421                 :     {
     422               5 :         const char *pszPR = strstr(pszKNP,"PR=");
     423               5 :         const char *pszGD = strstr(pszKNP,"GD=");
     424               5 :         const char *pszValue, *pszEnd = NULL;
     425               5 :         const char *pszGEOGCS = "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\"]]";
     426               5 :         CPLString osPP;
     427                 :         
     428                 :         // Capture the PP string.
     429               5 :         pszValue = strstr(pszKNP,"PP=");
     430               5 :         if( pszValue )
     431               5 :             pszEnd = strstr(pszValue,",");
     432               5 :         if( pszValue && pszEnd )
     433               5 :             osPP.assign(pszValue+3,pszEnd-pszValue-3);
     434                 :         
     435                 :         // Look at the datum
     436               5 :         if( pszGD == NULL )
     437                 :         {
     438                 :             /* no match. We'll default to EPSG:4326 */
     439                 :         }
     440               5 :         else if( EQUALN(pszGD,"GD=European 1950", 16) )
     441                 :         {
     442               0 :             pszGEOGCS = "GEOGCS[\"ED50\",DATUM[\"European_Datum_1950\",SPHEROID[\"International 1924\",6378388,297,AUTHORITY[\"EPSG\",\"7022\"]],TOWGS84[-87,-98,-121,0,0,0,0],AUTHORITY[\"EPSG\",\"6230\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4230\"]]";
     443                 :         }
     444                 : 
     445                 :         // Look at the projection
     446               5 :         if( pszPR == NULL )
     447                 :         {
     448                 :             /* no match */
     449                 :         }
     450               5 :         else if( EQUALN(pszPR,"PR=MERCATOR", 11) )
     451                 :         {
     452                 :             // We somewhat arbitrarily select our first GCPX as our 
     453                 :             // central meridian.  This is mostly helpful to ensure 
     454                 :             // that regions crossing the dateline will be contiguous 
     455                 :             // in mercator.
     456                 :             osUnderlyingSRS.Printf( "PROJCS[\"Global Mercator\",%s,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]]",
     457               5 :                 pszGEOGCS, (int) pasGCPList[0].dfGCPX );
     458                 :         }
     459                 : 
     460               0 :         else if( EQUALN(pszPR,"PR=TRANSVERSE MERCATOR", 22)
     461                 :                  && osPP.size() > 0 )
     462                 :         {
     463                 :             
     464                 :             osUnderlyingSRS.Printf( 
     465                 :                 "PROJCS[\"unnamed\",%s,PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",%s],PARAMETER[\"scale_factor\",1],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0]]",
     466               0 :                 pszGEOGCS, osPP.c_str() );
     467                 :         }
     468                 : 
     469               0 :         else if( EQUALN(pszPR,"PR=UNIVERSAL TRANSVERSE MERCATOR", 32)
     470                 :                  && osPP.size() > 0 )
     471                 :         {
     472                 :             // This is not *really* UTM unless the central meridian 
     473                 :             // matches a zone which it does not in some (most?) maps. 
     474                 :             osUnderlyingSRS.Printf( 
     475                 :                 "PROJCS[\"unnamed\",%s,PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",%s],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0]]", 
     476               0 :                 pszGEOGCS, osPP.c_str() );
     477                 :         }
     478                 : 
     479               0 :         else if( EQUALN(pszPR,"PR=POLYCONIC", 12) && osPP.size() > 0 )
     480                 :         {
     481                 :             osUnderlyingSRS.Printf( 
     482                 :                 "PROJCS[\"unnamed\",%s,PROJECTION[\"Polyconic\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",%s],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0]]", 
     483               0 :                 pszGEOGCS, osPP.c_str() );
     484                 :         }
     485                 :         
     486               0 :         else if( EQUALN(pszPR,"PR=LAMBERT CONFORMAL CONIC", 26) 
     487                 :                  && osPP.size() > 0 && pszKNQ != NULL )
     488                 :         {
     489               0 :             CPLString osP2, osP3;
     490                 :         
     491                 :             // Capture the KNQ/P2 string.
     492               0 :             pszValue = strstr(pszKNQ,"P2=");
     493               0 :             if( pszValue )
     494               0 :                 pszEnd = strstr(pszValue,",");
     495               0 :             if( pszValue && pszEnd )
     496               0 :                 osP2.assign(pszValue+3,pszEnd-pszValue-3);
     497                 :             
     498                 :             // Capture the KNQ/P3 string.
     499               0 :             pszValue = strstr(pszKNQ,"P3=");
     500               0 :             if( pszValue )
     501               0 :                 pszEnd = strstr(pszValue,",");
     502               0 :             if( pszValue )
     503                 :             {
     504               0 :                 if( pszEnd )
     505               0 :                     osP3.assign(pszValue+3,pszEnd-pszValue-3);
     506                 :                 else
     507               0 :                     osP3.assign(pszValue+3);
     508                 :             }
     509                 : 
     510               0 :             if( osP2.size() > 0 && osP3.size() > 0 )
     511                 :                 osUnderlyingSRS.Printf( 
     512                 :                     "PROJCS[\"unnamed\",%s,PROJECTION[\"Lambert_Conformal_Conic_2SP\"],PARAMETER[\"standard_parallel_1\",%s],PARAMETER[\"standard_parallel_2\",%s],PARAMETER[\"latitude_of_origin\",0.0],PARAMETER[\"central_meridian\",%s],PARAMETER[\"false_easting\",0.0],PARAMETER[\"false_northing\",0.0]]",
     513               0 :                     pszGEOGCS, osP2.c_str(), osP3.c_str(), osPP.c_str() );
     514                 : 
     515               5 :         }
     516                 :     }
     517                 : 
     518                 : /* -------------------------------------------------------------------- */
     519                 : /*      If we got an alternate underlying coordinate system, try        */
     520                 : /*      converting the GCPs to that coordinate system.                  */
     521                 : /* -------------------------------------------------------------------- */
     522               5 :     if( osUnderlyingSRS.length() > 0 )
     523                 :     {
     524               5 :         OGRSpatialReference oGeog_SRS, oProjected_SRS;
     525                 :         OGRCoordinateTransformation *poCT;
     526                 :         
     527               5 :         oProjected_SRS.SetFromUserInput( osUnderlyingSRS );
     528               5 :         oGeog_SRS.CopyGeogCSFrom( &oProjected_SRS );
     529                 :         
     530                 :         poCT = OGRCreateCoordinateTransformation( &oGeog_SRS, 
     531               5 :                                                   &oProjected_SRS );
     532               5 :         if( poCT != NULL )
     533                 :         {
     534               5 :             for( i = 0; i < nGCPCount; i++ )
     535                 :             {
     536                 :                 poCT->Transform( 1, 
     537               0 :                                  &(pasGCPList[i].dfGCPX), 
     538               0 :                                  &(pasGCPList[i].dfGCPY), 
     539               0 :                                  &(pasGCPList[i].dfGCPZ) );
     540                 :             }
     541                 : 
     542               5 :             osGCPProjection = osUnderlyingSRS;
     543                 : 
     544               5 :             delete poCT;
     545                 :         }
     546                 :         else
     547               0 :             CPLErrorReset();
     548                 :     }
     549                 : 
     550                 : /* -------------------------------------------------------------------- */
     551                 : /*      Attempt to prepare a geotransform from the GCPs.                */
     552                 : /* -------------------------------------------------------------------- */
     553               5 :     if( GDALGCPsToGeoTransform( nGCPCount, pasGCPList, adfGeoTransform, 
     554                 :                                 FALSE ) )
     555                 :     {
     556               0 :         bGeoTransformSet = TRUE;
     557               5 :     }
     558               5 : }
     559                 : 
     560                 : /************************************************************************/
     561                 : /*                           ScanForGCPsNos()                           */
     562                 : /*                                                                      */
     563                 : /*      Nos files have an accompanying .geo file, that contains some    */
     564                 : /*      of the information normally contained in the header section     */
     565                 : /*      with BSB files. we try and open a file with the same name,      */
     566                 : /*      but a .geo extension, and look for lines like...                */
     567                 : /*      PointX=long lat line pixel    (using the same naming system     */
     568                 : /*      as BSB) Point1=-22.0000 64.250000 197 744                       */
     569                 : /************************************************************************/
     570                 : 
     571               0 : void BSBDataset::ScanForGCPsNos( const char *pszFilename )
     572                 : {
     573                 :     char **Tokens;
     574                 :     const char *geofile;
     575                 :     const char *extension;
     576               0 :     int fileGCPCount=0;
     577                 : 
     578               0 :     extension = CPLGetExtension(pszFilename);
     579                 : 
     580                 :     // pseudointelligently try and guess whether we want a .geo or a .GEO
     581               0 :     if (extension[1] == 'O')
     582                 :     {
     583               0 :         geofile = CPLResetExtension( pszFilename, "GEO");
     584                 :     } else {
     585               0 :         geofile = CPLResetExtension( pszFilename, "geo");
     586                 :     }
     587                 : 
     588               0 :     FILE *gfp = VSIFOpen( geofile, "r" );  // Text files
     589               0 :     if( gfp == NULL )
     590                 :     {
     591                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     592               0 :                   "Couldn't find a matching .GEO file: %s", geofile );
     593               0 :         return;
     594                 :     }
     595                 : 
     596               0 :     char *thisLine = (char *) CPLMalloc( 80 ); // FIXME
     597                 : 
     598                 :     // Count the GCPs (reference points) and seek the file pointer 'gfp' to the starting point
     599               0 :     while (fgets(thisLine, 80, gfp))
     600                 :     {
     601               0 :         if( EQUALN(thisLine, "Point", 5) )
     602               0 :             fileGCPCount++;
     603                 :     }
     604               0 :     VSIRewind( gfp );
     605                 : 
     606                 :     // Memory has not been allocated to fileGCPCount yet
     607               0 :     pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),fileGCPCount+1);
     608                 : 
     609               0 :     while (fgets(thisLine, 80, gfp))
     610                 :     {
     611               0 :         if( EQUALN(thisLine, "Point", 5) )
     612                 :         {
     613                 :             // got a point line, turn it into a gcp
     614               0 :             Tokens = CSLTokenizeStringComplex(thisLine, "= ", FALSE, FALSE);
     615               0 :             if (CSLCount(Tokens) >= 5)
     616                 :             {
     617               0 :                 GDALInitGCPs( 1, pasGCPList + nGCPCount );
     618               0 :                 pasGCPList[nGCPCount].dfGCPX = atof(Tokens[1]);
     619               0 :                 pasGCPList[nGCPCount].dfGCPY = atof(Tokens[2]);
     620               0 :                 pasGCPList[nGCPCount].dfGCPPixel = atof(Tokens[4]);
     621               0 :                 pasGCPList[nGCPCount].dfGCPLine = atof(Tokens[3]);
     622                 : 
     623               0 :                 CPLFree( pasGCPList[nGCPCount].pszId );
     624                 :                 char  szName[50];
     625               0 :                 sprintf( szName, "GCP_%d", nGCPCount+1 );
     626               0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup( szName );
     627                 : 
     628               0 :                 nGCPCount++;
     629                 :             }
     630               0 :             CSLDestroy(Tokens);
     631                 :         }
     632                 :     }
     633                 : 
     634               0 :     CPLFree(thisLine);
     635               0 :     VSIFClose(gfp);
     636                 : }
     637                 : 
     638                 : 
     639                 : /************************************************************************/
     640                 : /*                            ScanForGCPsBSB()                          */
     641                 : /************************************************************************/
     642                 : 
     643               5 : void BSBDataset::ScanForGCPsBSB()
     644                 : {
     645                 : /* -------------------------------------------------------------------- */
     646                 : /*      Collect standalone GCPs.  They look like:                       */
     647                 : /*                                                                      */
     648                 : /*      REF/1,115,2727,32.346666666667,-60.881666666667     */
     649                 : /*      REF/n,pixel,line,lat,long                                       */
     650                 : /* -------------------------------------------------------------------- */
     651               5 :     int fileGCPCount=0;
     652                 :     int i;
     653                 : 
     654                 :     // Count the GCPs (reference points) in psInfo->papszHeader
     655             655 :     for( i = 0; psInfo->papszHeader[i] != NULL; i++ )
     656             650 :         if( EQUALN(psInfo->papszHeader[i],"REF/",4) )
     657               0 :             fileGCPCount++;
     658                 : 
     659                 :     // Memory has not been allocated to fileGCPCount yet
     660               5 :     pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),fileGCPCount+1);
     661                 : 
     662             655 :     for( i = 0; psInfo->papszHeader[i] != NULL; i++ )
     663                 :     {
     664                 :         char  **papszTokens;
     665                 :         char  szName[50];
     666                 : 
     667             650 :         if( !EQUALN(psInfo->papszHeader[i],"REF/",4) )
     668             650 :             continue;
     669                 : 
     670                 :         papszTokens = 
     671               0 :             CSLTokenizeStringComplex( psInfo->papszHeader[i]+4, ",", 
     672               0 :                                       FALSE, FALSE );
     673                 : 
     674               0 :         if( CSLCount(papszTokens) > 4 )
     675                 :         {
     676               0 :             GDALInitGCPs( 1, pasGCPList + nGCPCount );
     677                 : 
     678               0 :             pasGCPList[nGCPCount].dfGCPX = atof(papszTokens[4]);
     679               0 :             pasGCPList[nGCPCount].dfGCPY = atof(papszTokens[3]);
     680               0 :             pasGCPList[nGCPCount].dfGCPPixel = atof(papszTokens[1]);
     681               0 :             pasGCPList[nGCPCount].dfGCPLine = atof(papszTokens[2]);
     682                 : 
     683               0 :             CPLFree( pasGCPList[nGCPCount].pszId );
     684               0 :             if( CSLCount(papszTokens) > 5 )
     685                 :             {
     686               0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
     687                 :             }
     688                 :             else
     689                 :             {
     690               0 :                 sprintf( szName, "GCP_%d", nGCPCount+1 );
     691               0 :                 pasGCPList[nGCPCount].pszId = CPLStrdup( szName );
     692                 :             }
     693                 : 
     694               0 :             nGCPCount++;
     695                 :         }
     696               0 :         CSLDestroy( papszTokens );
     697                 :     }
     698               5 : }
     699                 : 
     700                 : /************************************************************************/
     701                 : /*                          IdentifyInternal()                          */
     702                 : /************************************************************************/
     703                 : 
     704           13662 : int BSBDataset::IdentifyInternal( GDALOpenInfo * poOpenInfo, bool& isNosOut )
     705                 : 
     706                 : {
     707                 : /* -------------------------------------------------------------------- */
     708                 : /*      Check for BSB/ keyword.                                         */
     709                 : /* -------------------------------------------------------------------- */
     710                 :     int     i;
     711           13662 :     isNosOut = false;
     712                 : 
     713           13662 :     if( poOpenInfo->nHeaderBytes < 1000 )
     714           12216 :         return FALSE;
     715                 : 
     716         1471299 :     for( i = 0; i < poOpenInfo->nHeaderBytes - 4; i++ )
     717                 :     {
     718         1476225 :         if( poOpenInfo->pabyHeader[i+0] == 'B'
     719            6350 :             && poOpenInfo->pabyHeader[i+1] == 'S'
     720              11 :             && poOpenInfo->pabyHeader[i+2] == 'B'
     721               6 :             && poOpenInfo->pabyHeader[i+3] == '/' )
     722               5 :             break;
     723         1474899 :         if( poOpenInfo->pabyHeader[i+0] == 'N'
     724            4909 :             && poOpenInfo->pabyHeader[i+1] == 'O'
     725             129 :             && poOpenInfo->pabyHeader[i+2] == 'S'
     726               8 :             && poOpenInfo->pabyHeader[i+3] == '/' )
     727                 :         {
     728               0 :             isNosOut = true;
     729               0 :             break;
     730                 :         }
     731         1471755 :         if( poOpenInfo->pabyHeader[i+0] == 'W'
     732            1871 :             && poOpenInfo->pabyHeader[i+1] == 'X'
     733              31 :             && poOpenInfo->pabyHeader[i+2] == '\\'
     734               0 :             && poOpenInfo->pabyHeader[i+3] == '8' )
     735               0 :             break;
     736                 :     }
     737                 : 
     738            1446 :     if( i == poOpenInfo->nHeaderBytes - 4 )
     739            1441 :         return FALSE;
     740                 : 
     741                 :     /* Additional test to avoid false positive. See #2881 */
     742               5 :     const char* pszRA = strstr((const char*)poOpenInfo->pabyHeader + i, "RA=");
     743               5 :     if (pszRA == NULL) /* This may be a NO1 file */
     744               0 :         pszRA = strstr((const char*)poOpenInfo->pabyHeader + i, "[JF");
     745               5 :     if (pszRA == NULL || pszRA - ((const char*)poOpenInfo->pabyHeader + i) > 100 )
     746               0 :         return FALSE;
     747                 : 
     748               5 :     return TRUE;
     749                 : }
     750                 : 
     751                 : /************************************************************************/
     752                 : /*                              Identify()                              */
     753                 : /************************************************************************/
     754                 : 
     755           10094 : int BSBDataset::Identify( GDALOpenInfo * poOpenInfo )
     756                 : 
     757                 : {
     758                 :     bool isNos;
     759           10094 :     return IdentifyInternal(poOpenInfo, isNos);
     760                 : }
     761                 : 
     762                 : /************************************************************************/
     763                 : /*                                Open()                                */
     764                 : /************************************************************************/
     765                 : 
     766            3568 : GDALDataset *BSBDataset::Open( GDALOpenInfo * poOpenInfo )
     767                 : 
     768                 : {
     769            3568 :     bool        isNos = false;
     770            3568 :     if (!IdentifyInternal(poOpenInfo, isNos))
     771            3563 :         return NULL;
     772                 : 
     773               5 :     if( poOpenInfo->eAccess == GA_Update )
     774                 :     {
     775                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     776                 :                   "The BSB driver does not support update access to existing"
     777               0 :                   " datasets.\n" );
     778               0 :         return NULL;
     779                 :     }
     780                 : 
     781                 : /* -------------------------------------------------------------------- */
     782                 : /*      Create a corresponding GDALDataset.                             */
     783                 : /* -------------------------------------------------------------------- */
     784                 :     BSBDataset  *poDS;
     785                 : 
     786               5 :     poDS = new BSBDataset();
     787                 : 
     788                 : /* -------------------------------------------------------------------- */
     789                 : /*      Open the file.                                                  */
     790                 : /* -------------------------------------------------------------------- */
     791               5 :     poDS->psInfo = BSBOpen( poOpenInfo->pszFilename );
     792               5 :     if( poDS->psInfo == NULL )
     793                 :     {
     794               0 :         delete poDS;
     795               0 :         return NULL;
     796                 :     }
     797                 : 
     798               5 :     poDS->nRasterXSize = poDS->psInfo->nXSize;
     799               5 :     poDS->nRasterYSize = poDS->psInfo->nYSize;
     800                 : 
     801                 : /* -------------------------------------------------------------------- */
     802                 : /*      Create band information objects.                                */
     803                 : /* -------------------------------------------------------------------- */
     804               5 :     poDS->SetBand( 1, new BSBRasterBand( poDS ));
     805                 : 
     806               5 :     poDS->ScanForGCPs( isNos, poOpenInfo->pszFilename );
     807                 : 
     808                 : /* -------------------------------------------------------------------- */
     809                 : /*      Initialize any PAM information.                                 */
     810                 : /* -------------------------------------------------------------------- */
     811               5 :     poDS->SetDescription( poOpenInfo->pszFilename );
     812               5 :     poDS->TryLoadXML();
     813                 : 
     814               5 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     815                 : 
     816               5 :     return( poDS );
     817                 : }
     818                 : 
     819                 : /************************************************************************/
     820                 : /*                            GetGCPCount()                             */
     821                 : /************************************************************************/
     822                 : 
     823               0 : int BSBDataset::GetGCPCount()
     824                 : 
     825                 : {
     826               0 :     return nGCPCount;
     827                 : }
     828                 : 
     829                 : /************************************************************************/
     830                 : /*                          GetGCPProjection()                          */
     831                 : /************************************************************************/
     832                 : 
     833               0 : const char *BSBDataset::GetGCPProjection()
     834                 : 
     835                 : {
     836               0 :     return osGCPProjection;
     837                 : }
     838                 : 
     839                 : /************************************************************************/
     840                 : /*                               GetGCP()                               */
     841                 : /************************************************************************/
     842                 : 
     843               0 : const GDAL_GCP *BSBDataset::GetGCPs()
     844                 : 
     845                 : {
     846               0 :     return pasGCPList;
     847                 : }
     848                 : 
     849                 : #ifdef BSB_CREATE
     850                 : 
     851                 : /************************************************************************/
     852                 : /*                             BSBIsSRSOK()                             */
     853                 : /************************************************************************/
     854                 : 
     855                 : static int BSBIsSRSOK(const char *pszWKT)
     856                 : {
     857                 :     int bOK = FALSE;
     858                 :     OGRSpatialReference oSRS, oSRS_WGS84, oSRS_NAD83;
     859                 : 
     860                 :     if( pszWKT != NULL && pszWKT[0] != '\0' )
     861                 :     {
     862                 :         char* pszTmpWKT = (char*)pszWKT;
     863                 :         oSRS.importFromWkt( &pszTmpWKT );
     864                 : 
     865                 :         oSRS_WGS84.SetWellKnownGeogCS( "WGS84" );
     866                 :         oSRS_NAD83.SetWellKnownGeogCS( "NAD83" );
     867                 :         if ( (oSRS.IsSameGeogCS(&oSRS_WGS84) || oSRS.IsSameGeogCS(&oSRS_NAD83)) &&
     868                 :               oSRS.IsGeographic() && oSRS.GetPrimeMeridian() == 0.0 )
     869                 :         {
     870                 :             bOK = TRUE;
     871                 :         }
     872                 :     }
     873                 : 
     874                 :     if (!bOK)
     875                 :     {
     876                 :         CPLError(CE_Warning, CPLE_NotSupported,
     877                 :                 "BSB only supports WGS84 or NAD83 geographic projections.\n");
     878                 :     }
     879                 : 
     880                 :     return bOK;
     881                 : }
     882                 : 
     883                 : /************************************************************************/
     884                 : /*                           BSBCreateCopy()                            */
     885                 : /************************************************************************/
     886                 : 
     887                 : static GDALDataset *
     888                 : BSBCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
     889                 :                int bStrict, char ** papszOptions, 
     890                 :                GDALProgressFunc pfnProgress, void * pProgressData )
     891                 : 
     892                 : {
     893                 :     int  nBands = poSrcDS->GetRasterCount();
     894                 :     int  nXSize = poSrcDS->GetRasterXSize();
     895                 :     int  nYSize = poSrcDS->GetRasterYSize();
     896                 : 
     897                 : /* -------------------------------------------------------------------- */
     898                 : /*      Some some rudimentary checks                                    */
     899                 : /* -------------------------------------------------------------------- */
     900                 :     if( nBands != 1 )
     901                 :     {
     902                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     903                 :                   "BSB driver only supports one band images.\n" );
     904                 : 
     905                 :         return NULL;
     906                 :     }
     907                 : 
     908                 :     if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte 
     909                 :         && bStrict )
     910                 :     {
     911                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     912                 :                   "BSB driver doesn't support data type %s. "
     913                 :                   "Only eight bit bands supported.\n", 
     914                 :                   GDALGetDataTypeName( 
     915                 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
     916                 : 
     917                 :         return NULL;
     918                 :     }
     919                 : 
     920                 : /* -------------------------------------------------------------------- */
     921                 : /*      Open the output file.                                           */
     922                 : /* -------------------------------------------------------------------- */
     923                 :     BSBInfo *psBSB;
     924                 : 
     925                 :     psBSB = BSBCreate( pszFilename, 0, 200, nXSize, nYSize );
     926                 :     if( psBSB == NULL )
     927                 :         return NULL;
     928                 : 
     929                 : /* -------------------------------------------------------------------- */
     930                 : /*      Prepare initial color table.colortable.                         */
     931                 : /* -------------------------------------------------------------------- */
     932                 :     GDALRasterBand  *poBand = poSrcDS->GetRasterBand(1);
     933                 :     int     iColor;
     934                 :     unsigned char       abyPCT[771];
     935                 :     int                 nPCTSize;
     936                 :     int                 anRemap[256];
     937                 : 
     938                 :     abyPCT[0] = 0;
     939                 :     abyPCT[1] = 0;
     940                 :     abyPCT[2] = 0;
     941                 : 
     942                 :     if( poBand->GetColorTable() == NULL )
     943                 :     {
     944                 :         /* map greyscale down to 63 grey levels. */
     945                 :         for( iColor = 0; iColor < 256; iColor++ )
     946                 :         {
     947                 :             int nOutValue = (int) (iColor / 4.1) + 1;
     948                 : 
     949                 :             anRemap[iColor] = nOutValue;
     950                 :             abyPCT[nOutValue*3 + 0] = (unsigned char) iColor;
     951                 :             abyPCT[nOutValue*3 + 1] = (unsigned char) iColor;
     952                 :             abyPCT[nOutValue*3 + 2] = (unsigned char) iColor;
     953                 :         }
     954                 :         nPCTSize = 64;
     955                 :     }
     956                 :     else
     957                 :     {
     958                 :         GDALColorTable  *poCT = poBand->GetColorTable();
     959                 :         int nColorTableSize = poCT->GetColorEntryCount();
     960                 :         if (nColorTableSize > 255)
     961                 :             nColorTableSize = 255;
     962                 : 
     963                 :         for( iColor = 0; iColor < nColorTableSize; iColor++ )
     964                 :         {
     965                 :             GDALColorEntry  sEntry;
     966                 : 
     967                 :             poCT->GetColorEntryAsRGB( iColor, &sEntry );
     968                 : 
     969                 :             anRemap[iColor] = iColor + 1;
     970                 :             abyPCT[(iColor+1)*3 + 0] = (unsigned char) sEntry.c1;
     971                 :             abyPCT[(iColor+1)*3 + 1] = (unsigned char) sEntry.c2;
     972                 :             abyPCT[(iColor+1)*3 + 2] = (unsigned char) sEntry.c3;
     973                 :         }
     974                 : 
     975                 :         nPCTSize = nColorTableSize + 1;
     976                 : 
     977                 :         // Add entries for pixel values which apparently will not occur.
     978                 :         for( iColor = nPCTSize; iColor < 256; iColor++ )
     979                 :             anRemap[iColor] = 1;
     980                 :     }
     981                 : 
     982                 : /* -------------------------------------------------------------------- */
     983                 : /*      Boil out all duplicate entries.                                 */
     984                 : /* -------------------------------------------------------------------- */
     985                 :     int  i;
     986                 : 
     987                 :     for( i = 1; i < nPCTSize-1; i++ )
     988                 :     {
     989                 :         int  j;
     990                 : 
     991                 :         for( j = i+1; j < nPCTSize; j++ )
     992                 :         {
     993                 :             if( abyPCT[i*3+0] == abyPCT[j*3+0] 
     994                 :                 && abyPCT[i*3+1] == abyPCT[j*3+1] 
     995                 :                 && abyPCT[i*3+2] == abyPCT[j*3+2] )
     996                 :             {
     997                 :                 int   k;
     998                 : 
     999                 :                 nPCTSize--;
    1000                 :                 abyPCT[j*3+0] = abyPCT[nPCTSize*3+0];
    1001                 :                 abyPCT[j*3+1] = abyPCT[nPCTSize*3+1];
    1002                 :                 abyPCT[j*3+2] = abyPCT[nPCTSize*3+2];
    1003                 : 
    1004                 :                 for( k = 0; k < 256; k++ )
    1005                 :                 {
    1006                 :                     // merge matching entries.
    1007                 :                     if( anRemap[k] == j )
    1008                 :                         anRemap[k] = i;
    1009                 : 
    1010                 :                     // shift the last PCT entry into the new hole.
    1011                 :                     if( anRemap[k] == nPCTSize )
    1012                 :                         anRemap[k] = j;
    1013                 :                 }
    1014                 :             }
    1015                 :         }
    1016                 :     }
    1017                 : 
    1018                 : /* -------------------------------------------------------------------- */
    1019                 : /*      Boil out all duplicate entries.                                 */
    1020                 : /* -------------------------------------------------------------------- */
    1021                 :     if( nPCTSize > 128 )
    1022                 :     {
    1023                 :         CPLError( CE_Warning, CPLE_AppDefined,
    1024                 :                   "Having to merge color table entries to reduce %d real\n"
    1025                 :                   "color table entries down to 127 values.", 
    1026                 :                   nPCTSize );
    1027                 :     }
    1028                 : 
    1029                 :     while( nPCTSize > 128 )
    1030                 :     {
    1031                 :         int nBestRange = 768;
    1032                 :         int iBestMatch1=-1, iBestMatch2=-1;
    1033                 : 
    1034                 :         // Find the closest pair of color table entries.
    1035                 : 
    1036                 :         for( i = 1; i < nPCTSize-1; i++ )
    1037                 :         {
    1038                 :             int  j;
    1039                 :             
    1040                 :             for( j = i+1; j < nPCTSize; j++ )
    1041                 :             {
    1042                 :                 int nRange = ABS(abyPCT[i*3+0] - abyPCT[j*3+0])
    1043                 :                     + ABS(abyPCT[i*3+1] - abyPCT[j*3+1])
    1044                 :                     + ABS(abyPCT[i*3+2] - abyPCT[j*3+2]);
    1045                 : 
    1046                 :                 if( nRange < nBestRange )
    1047                 :                 {
    1048                 :                     iBestMatch1 = i;
    1049                 :                     iBestMatch2 = j;
    1050                 :                     nBestRange = nRange;
    1051                 :                 }
    1052                 :             }
    1053                 :         }
    1054                 : 
    1055                 :         // Merge the second entry into the first. 
    1056                 :         nPCTSize--;
    1057                 :         abyPCT[iBestMatch2*3+0] = abyPCT[nPCTSize*3+0];
    1058                 :         abyPCT[iBestMatch2*3+1] = abyPCT[nPCTSize*3+1];
    1059                 :         abyPCT[iBestMatch2*3+2] = abyPCT[nPCTSize*3+2];
    1060                 : 
    1061                 :         for( i = 0; i < 256; i++ )
    1062                 :         {
    1063                 :             // merge matching entries.
    1064                 :             if( anRemap[i] == iBestMatch2 )
    1065                 :                 anRemap[i] = iBestMatch1;
    1066                 :             
    1067                 :             // shift the last PCT entry into the new hole.
    1068                 :             if( anRemap[i] == nPCTSize )
    1069                 :                 anRemap[i] = iBestMatch2;
    1070                 :         }
    1071                 :     }
    1072                 : 
    1073                 : /* -------------------------------------------------------------------- */
    1074                 : /*      Write the PCT.                                                  */
    1075                 : /* -------------------------------------------------------------------- */
    1076                 :     if( !BSBWritePCT( psBSB, nPCTSize, abyPCT ) )
    1077                 :     {
    1078                 :         BSBClose( psBSB );
    1079                 :         return NULL;
    1080                 :     }
    1081                 : 
    1082                 : /* -------------------------------------------------------------------- */
    1083                 : /*      Write the GCPs.                                                 */
    1084                 : /* -------------------------------------------------------------------- */
    1085                 :     double adfGeoTransform[6];
    1086                 :     int nGCPCount = poSrcDS->GetGCPCount();
    1087                 :     if (nGCPCount)
    1088                 :     {
    1089                 :         const char* pszGCPProjection = poSrcDS->GetGCPProjection();
    1090                 :         if ( BSBIsSRSOK(pszGCPProjection) )
    1091                 :         {
    1092                 :             const GDAL_GCP * pasGCPList = poSrcDS->GetGCPs();
    1093                 :             for( i = 0; i < nGCPCount; i++ )
    1094                 :             {
    1095                 :                 VSIFPrintfL( psBSB->fp, 
    1096                 :                             "REF/%d,%f,%f,%f,%f\n", 
    1097                 :                             i+1,
    1098                 :                             pasGCPList[i].dfGCPPixel, pasGCPList[i].dfGCPLine,
    1099                 :                             pasGCPList[i].dfGCPY, pasGCPList[i].dfGCPX);
    1100                 :             }
    1101                 :         }
    1102                 :     }
    1103                 :     else if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None)
    1104                 :     {
    1105                 :         const char* pszProjection = poSrcDS->GetProjectionRef();
    1106                 :         if ( BSBIsSRSOK(pszProjection) )
    1107                 :         {
    1108                 :             VSIFPrintfL( psBSB->fp, 
    1109                 :                         "REF/%d,%d,%d,%f,%f\n",
    1110                 :                         1,
    1111                 :                         0, 0,
    1112                 :                         adfGeoTransform[3] + 0 * adfGeoTransform[4] + 0 * adfGeoTransform[5],
    1113                 :                         adfGeoTransform[0] + 0 * adfGeoTransform[1] + 0 * adfGeoTransform[2]);
    1114                 :             VSIFPrintfL( psBSB->fp, 
    1115                 :                         "REF/%d,%d,%d,%f,%f\n",
    1116                 :                         2,
    1117                 :                         nXSize, 0,
    1118                 :                         adfGeoTransform[3] + nXSize * adfGeoTransform[4] + 0 * adfGeoTransform[5],
    1119                 :                         adfGeoTransform[0] + nXSize * adfGeoTransform[1] + 0 * adfGeoTransform[2]);
    1120                 :             VSIFPrintfL( psBSB->fp, 
    1121                 :                         "REF/%d,%d,%d,%f,%f\n",
    1122                 :                         3,
    1123                 :                         nXSize, nYSize,
    1124                 :                         adfGeoTransform[3] + nXSize * adfGeoTransform[4] + nYSize * adfGeoTransform[5],
    1125                 :                         adfGeoTransform[0] + nXSize * adfGeoTransform[1] + nYSize * adfGeoTransform[2]);
    1126                 :             VSIFPrintfL( psBSB->fp, 
    1127                 :                         "REF/%d,%d,%d,%f,%f\n",
    1128                 :                         4,
    1129                 :                         0, nYSize,
    1130                 :                         adfGeoTransform[3] + 0 * adfGeoTransform[4] + nYSize * adfGeoTransform[5],
    1131                 :                         adfGeoTransform[0] + 0 * adfGeoTransform[1] + nYSize * adfGeoTransform[2]);
    1132                 :         }
    1133                 :     }
    1134                 : 
    1135                 : /* -------------------------------------------------------------------- */
    1136                 : /*      Loop over image, copying image data.                            */
    1137                 : /* -------------------------------------------------------------------- */
    1138                 :     GByte   *pabyScanline;
    1139                 :     CPLErr      eErr = CE_None;
    1140                 : 
    1141                 :     pabyScanline = (GByte *) CPLMalloc( nXSize );
    1142                 : 
    1143                 :     for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )
    1144                 :     {
    1145                 :         eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
    1146                 :                                  pabyScanline, nXSize, 1, GDT_Byte,
    1147                 :                                  nBands, nBands * nXSize );
    1148                 :         if( eErr == CE_None )
    1149                 :         {
    1150                 :             for( i = 0; i < nXSize; i++ )
    1151                 :                 pabyScanline[i] = (GByte) anRemap[pabyScanline[i]];
    1152                 : 
    1153                 :             if( !BSBWriteScanline( psBSB, pabyScanline ) )
    1154                 :                 eErr = CE_Failure;
    1155                 :         }
    1156                 :     }
    1157                 : 
    1158                 :     CPLFree( pabyScanline );
    1159                 : 
    1160                 : /* -------------------------------------------------------------------- */
    1161                 : /*      cleanup                                                         */
    1162                 : /* -------------------------------------------------------------------- */
    1163                 :     BSBClose( psBSB );
    1164                 : 
    1165                 :     if( eErr != CE_None )
    1166                 :     {
    1167                 :         VSIUnlink( pszFilename );
    1168                 :         return NULL;
    1169                 :     }
    1170                 :     else
    1171                 :         return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
    1172                 : }
    1173                 : #endif
    1174                 : 
    1175                 : /************************************************************************/
    1176                 : /*                        GDALRegister_BSB()                            */
    1177                 : /************************************************************************/
    1178                 : 
    1179             582 : void GDALRegister_BSB()
    1180                 : 
    1181                 : {
    1182                 :     GDALDriver  *poDriver;
    1183                 : 
    1184             582 :     if( GDALGetDriverByName( "BSB" ) == NULL )
    1185                 :     {
    1186             561 :         poDriver = new GDALDriver();
    1187                 :         
    1188             561 :         poDriver->SetDescription( "BSB" );
    1189                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1190             561 :                                    "Maptech BSB Nautical Charts" );
    1191                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1192             561 :                                    "frmt_various.html#BSB" );
    1193             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1194                 : #ifdef BSB_CREATE
    1195                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
    1196                 : #endif
    1197             561 :         poDriver->pfnOpen = BSBDataset::Open;
    1198             561 :         poDriver->pfnIdentify = BSBDataset::Identify;
    1199                 : #ifdef BSB_CREATE
    1200                 :         poDriver->pfnCreateCopy = BSBCreateCopy;
    1201                 : #endif
    1202                 : 
    1203             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1204                 :     }
    1205             582 : }

Generated by: LCOV version 1.7