LCOV - code coverage report
Current view: directory - frmts/gta - gtadataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 700 576 82.3 %
Date: 2012-04-28 Functions: 50 34 68.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gtadataset.cpp 23475 2011-12-05 22:44:57Z rouault $
       3                 :  *
       4                 :  * Project:  GTA read/write Driver
       5                 :  * Purpose:  GDAL bindings over GTA library.
       6                 :  * Author:   Martin Lambers, marlam@marlam.de
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, 2011, Martin Lambers <marlam@marlam.de>
      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                 : /*
      31                 :  * This driver supports reading and writing GTAs (Generic Tagged Arrays). See
      32                 :  * http://www.nongnu.org/gta/ for details on this format.
      33                 :  *
      34                 :  * Supported Features:
      35                 :  * - CreateCopy().
      36                 :  * - GTA compression can be set.
      37                 :  * - Raster data is updatable for uncompressed GTAs.
      38                 :  * - All input/output is routed through the VSIF*L functions
      39                 :  *   (GDAL_DCAP_VIRTUALIO is set to "YES").
      40                 :  * - All kinds of metadata are supported (see tag list below).
      41                 :  *
      42                 :  * Limitations:
      43                 :  * - Only uncompressed GTAs can be updated.
      44                 :  * - Only raster data updates are possible; metadata cannot be changed.
      45                 :  * - Color palettes are not supported.
      46                 :  * - CInt16 is stored as gta::cfloat32, and CInt32 as gta::cfloat64.
      47                 :  * - GDAL metadata is assumed to be in UTF-8 encoding, so that no conversion is
      48                 :  *   necessary to store it in GTA tags. I'm not sure that this is correct, but
      49                 :  *   since some metadata might not be representable in the local encoding (e.g.
      50                 :  *   a chinese description in latin1), using UTF-8 seems reasonable.
      51                 :  *
      52                 :  * The following could be implemented, but currently is not:
      53                 :  * - Allow metadata updates by using a special GDAL/METADATA_BUFFER tag that
      54                 :  *   contains a number of spaces as a placeholder for additional metadata, so
      55                 :  *   that the header size on disk can be kept constant.
      56                 :  * - Implement Create().
      57                 :  * - Implement AddBand() for uncompressed GTAs. But this would be inefficient:
      58                 :  *   the old data would need to be copied to a temporary file, and then copied
      59                 :  *   back while extending it with the new band.
      60                 :  * - When strict conversion is requested, store CInt16 in 2 x gta::int16 and
      61                 :  *   CInt32 in 2 x gta::int32, and mark these components with special flags so
      62                 :  *   that this is reverted when opening the GTA.
      63                 :  * - Support color palettes by storing the palette in special tags.
      64                 :  *
      65                 :  * This driver supports the following standard GTA tags:
      66                 :  * DESCRIPTION
      67                 :  * INTERPRETATION
      68                 :  * NO_DATA_VALUE
      69                 :  * MIN_VALUE
      70                 :  * MAX_VALUE
      71                 :  * UNIT
      72                 :  *
      73                 :  * Additionally, the following tags are used for GDAL-specific metadata:
      74                 :  * GDAL/PROJECTION      (WKT)
      75                 :  * GDAL/GEO_TRANSFORM   (6 doubles)
      76                 :  * GDAL/OFFSET          (1 double)
      77                 :  * GDAL/SCALE           (1 double)
      78                 :  * GDAL/GCP_PROJECTION  (WKT)
      79                 :  * GDAL/GCP_COUNT       (1 int > 0)
      80                 :  * GDAL/GCP%d           (5 doubles)
      81                 :  * GDAL/GCP%d_INFO      (String)
      82                 :  * GDAL/CATEGORY_COUNT  (1 int > 0)
      83                 :  * GDAL/CATEGORY%d      (String)
      84                 :  * GDAL/META/DEFAULT/%s (String)
      85                 :  * GDAL/META/RCP/%s     (String)
      86                 :  */
      87                 : 
      88                 : #include <limits.h>
      89                 : #include "cpl_port.h" // for snprintf for MSVC
      90                 : #include <gta/gta.hpp>
      91                 : #include "gdal_pam.h"
      92                 : 
      93                 : CPL_CVSID("$Id: gtadataset.cpp 23475 2011-12-05 22:44:57Z rouault $");
      94                 : 
      95                 : CPL_C_START
      96                 : void    GDALRegister_GTA(void);
      97                 : CPL_C_END
      98                 : 
      99                 : 
     100                 : /************************************************************************/
     101                 : /* Helper functions                                                     */
     102                 : /************************************************************************/
     103                 : 
     104             216 : static void ScanDoubles( const char *pszString, double *padfDoubles, int nCount )
     105                 : 
     106                 : {
     107             216 :     char *pszRemainingString = (char *)pszString;
     108            1488 :     for( int i = 0; i < nCount; i++ )
     109                 :     {
     110            1272 :         padfDoubles[i] = 0.0;   // fallback value
     111            1272 :         padfDoubles[i] = CPLStrtod( pszRemainingString, &pszRemainingString );
     112                 :     }
     113             216 : }
     114                 : 
     115             382 : static CPLString PrintDoubles( const double *padfDoubles, int nCount )
     116                 : 
     117                 : {
     118             382 :     CPLString oString;
     119            1216 :     for( int i = 0; i < nCount; i++ )
     120                 :     {
     121             834 :         oString.FormatC( padfDoubles[i], "%.16g" );
     122             834 :         if( i < nCount - 1)
     123                 :         {
     124             452 :             oString += ' ';
     125                 :         }
     126                 :     }
     127               0 :     return oString;
     128                 : }
     129                 : 
     130                 : /************************************************************************/
     131                 : /* ==================================================================== */
     132                 : /* GTA custom IO class using GDAL's IO abstraction layer                */
     133                 : /* ==================================================================== */
     134                 : /************************************************************************/
     135                 : 
     136                 : class GTAIO : public gta::custom_io
     137                 : {
     138                 :   private:
     139                 :     VSILFILE *fp;
     140                 : 
     141                 :   public:
     142             292 :     GTAIO( ) throw ()
     143             292 :         : fp( NULL )
     144                 :     {
     145             292 :     }
     146             292 :     ~GTAIO( )
     147             292 :     {
     148             292 :         close( );
     149             292 :     }
     150                 : 
     151             292 :     int open( const char *pszFilename, const char *pszMode )
     152                 :     {
     153             292 :         fp = VSIFOpenL( pszFilename, pszMode );
     154             292 :         return ( fp == NULL ? -1 : 0 );
     155                 :     }
     156                 : 
     157             376 :     void close( )
     158                 :     {
     159             376 :         if( fp != NULL )
     160                 :         {
     161             288 :             VSIFCloseL( fp );
     162             288 :             fp = NULL;
     163                 :         }
     164             376 :     }
     165                 : 
     166             204 :     vsi_l_offset tell( )
     167                 :     {
     168             204 :         return VSIFTellL( fp );
     169                 :     }
     170                 : 
     171            2410 :     virtual size_t read(void *buffer, size_t size, bool *error) throw ()
     172               0 :     {
     173                 :         size_t s;
     174            2410 :         s = VSIFReadL( buffer, 1, size, fp );
     175            2410 :         if( s != size )
     176                 :         {
     177               0 :             errno = EIO;
     178               0 :             *error = true;
     179                 :         }
     180            2410 :         return size;
     181                 :     }
     182                 : 
     183             704 :     virtual size_t write(const void *buffer, size_t size, bool *error) throw ()
     184               0 :     {
     185                 :         size_t s;
     186             704 :         s = VSIFWriteL( buffer, 1, size, fp );
     187             704 :         if( s != size )
     188                 :         {
     189               0 :             errno = EIO;
     190               0 :             *error = true;
     191                 :         }
     192             704 :         return size;
     193                 :     }
     194                 : 
     195               0 :     virtual bool seekable() throw ()
     196                 :     {
     197               0 :         return true;
     198                 :     }
     199                 : 
     200            1400 :     virtual void seek(intmax_t offset, int whence, bool *error) throw ()
     201               0 :     {
     202                 :         int r;
     203            1400 :         r = VSIFSeekL( fp, offset, whence );
     204            1400 :         if( r != 0 )
     205                 :         {
     206               0 :             errno = EIO;
     207               0 :             *error = true;
     208                 :         }
     209            1400 :     }
     210                 : };
     211                 : 
     212                 : /************************************************************************/
     213                 : /* ==================================================================== */
     214                 : /*                              GTADataset                              */
     215                 : /* ==================================================================== */
     216                 : /************************************************************************/
     217                 : 
     218                 : class GTARasterBand;
     219                 : 
     220                 : class GTADataset : public GDALPamDataset
     221                 : {
     222                 :     friend class GTARasterBand;
     223                 : 
     224                 :   private:
     225                 :     // GTA input/output via VSIF*L functions
     226                 :     GTAIO       oGTAIO;
     227                 :     // GTA information
     228                 :     gta::header oHeader;
     229                 :     vsi_l_offset DataOffset;
     230                 :     // Metadata
     231                 :     bool        bHaveGeoTransform;
     232                 :     double      adfGeoTransform[6];
     233                 :     int         nGCPs;
     234                 :     char        *pszGCPProjection;
     235                 :     GDAL_GCP    *pasGCPs;
     236                 :     // Cached data block for block-based input/output
     237                 :     int         nLastBlockXOff, nLastBlockYOff;
     238                 :     void        *pBlock;
     239                 : 
     240                 :     // Block-based input/output of all bands at once. This is used
     241                 :     // by the GTARasterBand input/output functions.
     242                 :     CPLErr      ReadBlock( int, int );
     243                 :     CPLErr      WriteBlock( );
     244                 : 
     245                 :   public:
     246                 :                 GTADataset();
     247                 :                 ~GTADataset();
     248                 : 
     249                 :     static GDALDataset *Open( GDALOpenInfo * );
     250                 : 
     251                 :     CPLErr      GetGeoTransform( double * padfTransform );
     252                 :     CPLErr      SetGeoTransform( double * padfTransform );
     253                 : 
     254                 :     const char *GetProjectionRef( );
     255                 :     CPLErr      SetProjection( const char *pszProjection );
     256                 : 
     257                 :     int         GetGCPCount( );
     258                 :     const char *GetGCPProjection( );
     259                 :     const GDAL_GCP *GetGCPs( );
     260                 :     CPLErr      SetGCPs( int, const GDAL_GCP *, const char * );
     261                 : };
     262                 : 
     263                 : /************************************************************************/
     264                 : /* ==================================================================== */
     265                 : /*                            GTARasterBand                             */
     266                 : /* ==================================================================== */
     267                 : /************************************************************************/
     268                 : 
     269                 : class GTARasterBand : public GDALPamRasterBand
     270                 : {
     271                 :     friend class GTADataset;
     272                 :   private:
     273                 :     // Size of the component represented by this band
     274                 :     size_t      sComponentSize;
     275                 :     // Offset of the component represented by this band inside a GTA element
     276                 :     size_t      sComponentOffset;
     277                 :     // StringList for category names
     278                 :     char      **papszCategoryNames;
     279                 :     // StringList for metadata
     280                 :     char      **papszMetaData;
     281                 : 
     282                 :   public:
     283                 :                 GTARasterBand( GTADataset *, int );
     284                 :                 ~GTARasterBand( );
     285                 : 
     286                 :     CPLErr      IReadBlock( int, int, void * );
     287                 :     CPLErr      IWriteBlock( int, int, void * );
     288                 : 
     289                 :     char      **GetCategoryNames( );
     290                 :     CPLErr      SetCategoryNames( char ** );
     291                 : 
     292                 :     double      GetMinimum( int * );
     293                 :     double      GetMaximum( int * );
     294                 : 
     295                 :     double      GetNoDataValue( int * );
     296                 :     CPLErr      SetNoDataValue( double );
     297                 :     double      GetOffset( int * );
     298                 :     CPLErr      SetOffset( double );
     299                 :     double      GetScale( int * );
     300                 :     CPLErr      SetScale( double );
     301                 :     const char *GetUnitType( );
     302                 :     CPLErr      SetUnitType( const char * );
     303                 :     GDALColorInterp GetColorInterpretation( );
     304                 :     CPLErr      SetColorInterpretation( GDALColorInterp );
     305                 : };
     306                 : 
     307                 : /************************************************************************/
     308                 : /*                           GTARasterBand()                            */
     309                 : /************************************************************************/
     310                 : 
     311             332 : GTARasterBand::GTARasterBand( GTADataset *poDS, int nBand )
     312                 : 
     313                 : {
     314             332 :     this->poDS = poDS;
     315             332 :     this->nBand = nBand;
     316                 : 
     317                 :     // Data type
     318             332 :     switch( poDS->oHeader.component_type( nBand-1 ) )
     319                 :     {
     320                 :     case gta::int8:
     321               6 :         eDataType = GDT_Byte;
     322               6 :         SetMetadataItem("PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE");
     323               6 :         break;
     324                 :     case gta::uint8:
     325             250 :         eDataType = GDT_Byte;
     326             250 :         break;
     327                 :     case gta::int16:
     328               8 :         eDataType = GDT_Int16;
     329               8 :         break;
     330                 :     case gta::uint16:
     331               8 :         eDataType = GDT_UInt16;
     332               8 :         break;
     333                 :     case gta::int32:
     334               8 :         eDataType = GDT_Int32;
     335               8 :         break;
     336                 :     case gta::uint32:
     337               8 :         eDataType = GDT_UInt32;
     338               8 :         break;
     339                 :     case gta::float32:
     340               8 :         eDataType = GDT_Float32;
     341               8 :         break;
     342                 :     case gta::float64:
     343               8 :         eDataType = GDT_Float64;
     344               8 :         break;
     345                 :     case gta::cfloat32:
     346              14 :         eDataType = GDT_CFloat32;
     347              14 :         break;
     348                 :     case gta::cfloat64:
     349              14 :         eDataType = GDT_CFloat64;
     350                 :         break;
     351                 :     default:
     352                 :         // cannot happen because we checked this in GTADataset::Open()
     353                 :         break;
     354                 :     }
     355                 : 
     356                 :     // Block size
     357             332 :     nBlockXSize = poDS->GetRasterXSize();
     358             332 :     nBlockYSize = 1;
     359                 : 
     360                 :     // Component information
     361             332 :     sComponentSize = poDS->oHeader.component_size( nBand-1 );
     362             332 :     sComponentOffset = 0;
     363            1206 :     for( int i = 0; i < nBand-1; i++ )
     364                 :     {
     365             874 :         sComponentOffset += poDS->oHeader.component_size( i );
     366                 :     }
     367                 : 
     368                 :     // Metadata
     369             332 :     papszCategoryNames = NULL;
     370             332 :     papszMetaData = NULL;
     371             332 :     if( poDS->oHeader.component_taglist( nBand-1 ).get( "DESCRIPTION" ) )
     372                 :     {
     373               6 :         SetDescription( poDS->oHeader.component_taglist( nBand-1 ).get( "DESCRIPTION" ) );
     374                 :     }
     375            1378 :     for( uintmax_t i = 0; i < poDS->oHeader.component_taglist( nBand-1 ).tags(); i++)
     376                 :     {
     377            1046 :         const char *pszTagName = poDS->oHeader.component_taglist( nBand-1 ).name( i );
     378            1046 :         if( strncmp( pszTagName, "GDAL/META/", 10 ) == 0 )
     379                 :         {
     380              24 :             const char *pDomainEnd = strchr( pszTagName + 10, '/' );
     381              24 :             if( pDomainEnd && pDomainEnd - (pszTagName + 10) > 0 )
     382                 :             {
     383              24 :                 char *pszDomain = (char *)VSIMalloc( pDomainEnd - (pszTagName + 10) + 1 );
     384              24 :                 if( !pszDomain )
     385                 :                 {
     386               0 :                     continue;
     387                 :                 }
     388                 :                 int j;
     389             192 :                 for( j = 0; j < pDomainEnd - (pszTagName + 10); j++ )
     390                 :                 {
     391             168 :                     pszDomain[j] = pszTagName[10 + j];
     392                 :                 }
     393              24 :                 pszDomain[j] = '\0';
     394              24 :                 const char *pszName = pszTagName + 10 + j + 1;
     395              24 :                 const char *pszValue = poDS->oHeader.component_taglist( nBand-1 ).value( i );
     396                 :                 SetMetadataItem( pszName, pszValue,
     397              24 :                         strcmp( pszDomain, "DEFAULT" ) == 0 ? NULL : pszDomain );
     398              24 :                 VSIFree( pszDomain );
     399                 :             }
     400                 :         }
     401                 :     }
     402             332 : }
     403                 : 
     404                 : /************************************************************************/
     405                 : /*                           ~GTARasterBand()                           */
     406                 : /************************************************************************/
     407                 : 
     408             332 : GTARasterBand::~GTARasterBand( )
     409                 : 
     410                 : {
     411             332 :     CSLDestroy( papszCategoryNames );
     412             332 :     CSLDestroy( papszMetaData );
     413             332 : }
     414                 : 
     415                 : /************************************************************************/
     416                 : /*                             GetCategoryNames()                       */
     417                 : /************************************************************************/
     418                 : 
     419               4 : char **GTARasterBand::GetCategoryNames( )
     420                 : 
     421                 : {
     422               4 :     if( !papszCategoryNames )
     423                 :     {
     424               4 :         GTADataset *poGDS = (GTADataset *) poDS;
     425               4 :         const char *pszCatCount = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/CATEGORY_COUNT" );
     426               4 :         int nCatCount = 0;
     427               4 :         if( pszCatCount )
     428                 :         {
     429               4 :             nCatCount = atoi( pszCatCount );
     430                 :         }
     431               4 :         if( nCatCount > 0 )
     432                 :         {
     433              12 :             for( int i = 0; i < nCatCount; i++ )
     434                 :             {
     435                 :                 const char *pszCatName = poGDS->oHeader.component_taglist( nBand-1 ).get(
     436               8 :                         CPLSPrintf( "GDAL/CATEGORY%d", i ) );
     437               8 :                 papszCategoryNames = CSLAddString( papszCategoryNames, pszCatName ? pszCatName : "" );
     438                 :             }
     439                 :         }
     440                 :     }
     441               4 :     return papszCategoryNames;
     442                 : }
     443                 : 
     444                 : /************************************************************************/
     445                 : /*                             SetCategoryName()                        */
     446                 : /************************************************************************/
     447                 : 
     448               0 : CPLErr GTARasterBand::SetCategoryNames( char ** )
     449                 : 
     450                 : {
     451                 :     CPLError( CE_Warning, CPLE_NotSupported,
     452               0 :             "The GTA driver does not support metadata updates.\n" );
     453               0 :     return CE_Failure;
     454                 : }
     455                 : 
     456                 : /************************************************************************/
     457                 : /*                             GetMinimum()                             */
     458                 : /************************************************************************/
     459                 : 
     460               2 : double GTARasterBand::GetMinimum( int *pbSuccess )
     461                 : 
     462                 : {
     463               2 :     GTADataset *poGDS = (GTADataset *) poDS;
     464               2 :     const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "MIN_VALUE" );
     465               2 :     if( pszValue )
     466                 :     {
     467               2 :         if( pbSuccess )
     468               2 :             *pbSuccess = true;
     469               2 :         return CPLAtof( pszValue );
     470                 :     }
     471                 :     else
     472                 :     {
     473               0 :         return GDALRasterBand::GetMinimum( pbSuccess );
     474                 :     }
     475                 : }
     476                 : 
     477                 : /************************************************************************/
     478                 : /*                             GetMaximum()                             */
     479                 : /************************************************************************/
     480                 : 
     481               2 : double GTARasterBand::GetMaximum( int *pbSuccess  )
     482                 : 
     483                 : {
     484               2 :     GTADataset *poGDS = (GTADataset *) poDS;
     485               2 :     const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "MAX_VALUE" );
     486               2 :     if( pszValue )
     487                 :     {
     488               2 :         if( pbSuccess )
     489               2 :             *pbSuccess = true;
     490               2 :         return CPLAtof( pszValue );
     491                 :     }
     492                 :     else
     493                 :     {
     494               0 :         return GDALRasterBand::GetMaximum( pbSuccess );
     495                 :     }
     496                 : }
     497                 : 
     498                 : /************************************************************************/
     499                 : /*                             GetNoDataValue()                         */
     500                 : /************************************************************************/
     501                 : 
     502              56 : double GTARasterBand::GetNoDataValue( int *pbSuccess )
     503                 : 
     504                 : {
     505              56 :     GTADataset *poGDS = (GTADataset *) poDS;
     506              56 :     const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "NO_DATA_VALUE" );
     507              56 :     if( pszValue )
     508                 :     {
     509               4 :         if( pbSuccess )
     510               4 :             *pbSuccess = true;
     511               4 :         return CPLAtof( pszValue );
     512                 :     }
     513                 :     else
     514                 :     {
     515              52 :         return GDALRasterBand::GetNoDataValue( pbSuccess );
     516                 :     }
     517                 : }
     518                 : 
     519                 : /************************************************************************/
     520                 : /*                             SetNoDataValue()                         */
     521                 : /************************************************************************/
     522                 : 
     523               0 : CPLErr GTARasterBand::SetNoDataValue( double )
     524                 : 
     525                 : {
     526                 :     CPLError( CE_Warning, CPLE_NotSupported,
     527               0 :             "The GTA driver does not support metadata updates.\n" );
     528               0 :     return CE_Failure;
     529                 : }
     530                 : 
     531                 : /************************************************************************/
     532                 : /*                             GetOffset()                              */
     533                 : /************************************************************************/
     534                 : 
     535             142 : double GTARasterBand::GetOffset( int *pbSuccess )
     536                 : 
     537                 : {
     538             142 :     GTADataset *poGDS = (GTADataset *) poDS;
     539             142 :     const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/OFFSET" );
     540             142 :     if( pszValue )
     541                 :     {
     542             142 :         if( pbSuccess )
     543               2 :             *pbSuccess = true;
     544             142 :         return CPLAtof( pszValue );
     545                 :     }
     546                 :     else
     547                 :     {
     548               0 :         return GDALRasterBand::GetOffset( pbSuccess );
     549                 :     }
     550                 : }
     551                 : 
     552                 : /************************************************************************/
     553                 : /*                             SetOffset()                              */
     554                 : /************************************************************************/
     555                 : 
     556               0 : CPLErr GTARasterBand::SetOffset( double )
     557                 : 
     558                 : {
     559                 :     CPLError( CE_Warning, CPLE_NotSupported,
     560               0 :             "The GTA driver does not support metadata updates.\n" );
     561               0 :     return CE_Failure;
     562                 : }
     563                 : 
     564                 : /************************************************************************/
     565                 : /*                             GetScale()                               */
     566                 : /************************************************************************/
     567                 : 
     568             142 : double GTARasterBand::GetScale( int *pbSuccess )
     569                 : 
     570                 : {
     571             142 :     GTADataset *poGDS = (GTADataset *) poDS;
     572             142 :     const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "GDAL/SCALE" );
     573             142 :     if( pszValue )
     574                 :     {
     575             142 :         if( pbSuccess )
     576               2 :             *pbSuccess = true;
     577             142 :         return CPLAtof( pszValue );
     578                 :     }
     579                 :     else
     580                 :     {
     581               0 :         return GDALRasterBand::GetScale( pbSuccess );
     582                 :     }
     583                 : }
     584                 : 
     585                 : /************************************************************************/
     586                 : /*                             SetScale()                               */
     587                 : /************************************************************************/
     588                 : 
     589               0 : CPLErr GTARasterBand::SetScale( double )
     590                 : 
     591                 : {
     592                 :     CPLError( CE_Warning, CPLE_NotSupported,
     593               0 :             "The GTA driver does not support metadata updates.\n" );
     594               0 :     return CE_Failure;
     595                 : }
     596                 : 
     597                 : /************************************************************************/
     598                 : /*                             GetUnitType()                            */
     599                 : /************************************************************************/
     600                 : 
     601               4 : const char *GTARasterBand::GetUnitType( )
     602                 : 
     603                 : {
     604               4 :     GTADataset *poGDS = (GTADataset *) poDS;
     605               4 :     const char *pszValue = poGDS->oHeader.component_taglist( nBand-1 ).get( "UNIT" );
     606               4 :     return pszValue ? pszValue : "";
     607                 : }
     608                 : 
     609                 : /************************************************************************/
     610                 : /*                             SetUnitType()                            */
     611                 : /************************************************************************/
     612                 : 
     613               0 : CPLErr GTARasterBand::SetUnitType( const char * )
     614                 : 
     615                 : {
     616                 :     CPLError( CE_Warning, CPLE_NotSupported,
     617               0 :             "The GTA driver does not support metadata updates.\n" );
     618               0 :     return CE_Failure;
     619                 : }
     620                 : 
     621                 : /************************************************************************/
     622                 : /*                             GetColorInterpretation()                 */
     623                 : /************************************************************************/
     624                 : 
     625             158 : GDALColorInterp GTARasterBand::GetColorInterpretation( )
     626                 : 
     627                 : {
     628             158 :     GTADataset *poGDS = (GTADataset *) poDS;
     629                 :     const char *pszColorInterpretation =
     630                 :         poGDS->oHeader.component_taglist( nBand-1 ).get(
     631             158 :                 "INTERPRETATION" );
     632             158 :     if( pszColorInterpretation )
     633                 :     {
     634             156 :         if( EQUAL( pszColorInterpretation, "GRAY" ) )
     635              80 :             return GCI_GrayIndex ;
     636              76 :         else if ( EQUAL( pszColorInterpretation, "RED" ) )
     637              10 :             return GCI_RedBand ;
     638              66 :         else if ( EQUAL( pszColorInterpretation, "GREEN" ) )
     639              10 :             return GCI_GreenBand ;
     640              56 :         else if ( EQUAL( pszColorInterpretation, "BLUE" ) )
     641              10 :             return GCI_BlueBand ;
     642              46 :         else if ( EQUAL( pszColorInterpretation, "ALPHA" ) )
     643               6 :             return GCI_AlphaBand ;
     644              40 :         else if ( EQUAL( pszColorInterpretation, "HSL/H" ) )
     645               4 :             return GCI_HueBand ;
     646              36 :         else if ( EQUAL( pszColorInterpretation, "HSL/S" ) )
     647               4 :             return GCI_SaturationBand ;
     648              32 :         else if ( EQUAL( pszColorInterpretation, "HSL/L" ) )
     649               4 :             return GCI_LightnessBand ;
     650              28 :         else if ( EQUAL( pszColorInterpretation, "CMYK/C" ) )
     651               4 :             return GCI_CyanBand ;
     652              24 :         else if ( EQUAL( pszColorInterpretation, "CMYK/M" ) )
     653               4 :             return GCI_MagentaBand ;
     654              20 :         else if ( EQUAL( pszColorInterpretation, "CMYK/Y" ) )
     655               4 :             return GCI_YellowBand ;
     656              16 :         else if ( EQUAL( pszColorInterpretation, "CMYK/K" ) )
     657               4 :             return GCI_BlackBand ;
     658              12 :         else if ( EQUAL( pszColorInterpretation, "YCBCR/Y" ) )
     659               4 :             return GCI_YCbCr_YBand;
     660               8 :         else if ( EQUAL( pszColorInterpretation, "YCBCR/CB" ) )
     661               4 :             return GCI_YCbCr_CbBand;
     662               4 :         else if ( EQUAL( pszColorInterpretation, "YCBCR/CR" ) )
     663               4 :             return GCI_YCbCr_CrBand;
     664                 :     }
     665               2 :     return GCI_Undefined;
     666                 : }
     667                 : 
     668                 : /************************************************************************/
     669                 : /*                             SetColorInterpretation()                 */
     670                 : /************************************************************************/
     671                 : 
     672               0 : CPLErr GTARasterBand::SetColorInterpretation( GDALColorInterp )
     673                 : 
     674                 : {
     675                 :     CPLError( CE_Warning, CPLE_NotSupported,
     676               0 :             "The GTA driver does not support metadata updates.\n" );
     677               0 :     return CE_Failure;
     678                 : }
     679                 : 
     680                 : /************************************************************************/
     681                 : /*                             IReadBlock()                             */
     682                 : /************************************************************************/
     683                 : 
     684            1240 : CPLErr GTARasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     685                 :                                   void * pImage )
     686                 : 
     687                 : {
     688            1240 :     GTADataset *poGDS = (GTADataset *) poDS;
     689                 : 
     690                 :     // Read and cache block containing all bands at once
     691            1240 :     if( poGDS->ReadBlock( nBlockXOff, nBlockYOff ) != CE_None )
     692                 :     {
     693               0 :         return CE_Failure;
     694                 :     }
     695                 : 
     696            1240 :     char *pBlock = (char *)poGDS->pBlock;
     697            1240 :     if( poGDS->oHeader.compression() != gta::none )
     698                 :     {
     699                 :         // pBlock contains the complete data set. Add the offset into the
     700                 :         // requested block. This assumes that nBlockYSize == 1 and
     701                 :         // nBlockXSize == nRasterXSize.
     702               0 :         pBlock += nBlockYOff * nBlockXSize * poGDS->oHeader.element_size();
     703                 :     }
     704                 : 
     705                 :     // Copy the data for this band from the cached block
     706           32040 :     for( int i = 0; i < nBlockXSize; i++ )
     707                 :     {
     708           30800 :         char *pSrc = pBlock + i * poGDS->oHeader.element_size() + sComponentOffset;
     709           30800 :         char *pDst = (char *) pImage + i * sComponentSize;
     710           30800 :         memcpy( (void *) pDst, (void *) pSrc, sComponentSize );
     711                 :     }
     712                 : 
     713            1240 :     return CE_None;
     714                 : }
     715                 : 
     716                 : /************************************************************************/
     717                 : /*                             IWriteBlock()                            */
     718                 : /************************************************************************/
     719                 : 
     720              80 : CPLErr GTARasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     721                 :                                   void * pImage )
     722                 : 
     723                 : {
     724              80 :     GTADataset *poGDS = (GTADataset *) poDS;
     725                 : 
     726              80 :     if( poGDS->oHeader.compression() != gta::none )
     727                 :     {
     728                 :         CPLError( CE_Warning, CPLE_NotSupported,
     729               0 :                 "The GTA driver cannot update compressed GTAs.\n" );
     730               0 :         return CE_Failure;
     731                 :     }
     732                 : 
     733                 :     // Read and cache block containing all bands at once
     734              80 :     if( poGDS->ReadBlock( nBlockXOff, nBlockYOff ) != CE_None )
     735                 :     {
     736               0 :         return CE_Failure;
     737                 :     }
     738              80 :     char *pBlock = (char *)poGDS->pBlock;
     739                 : 
     740                 :     // Copy the data for this band into the cached block
     741            1680 :     for( int i = 0; i < nBlockXSize; i++ )
     742                 :     {
     743            1600 :         char *pSrc = (char *) pImage + i * sComponentSize;
     744            1600 :         char *pDst = pBlock + i * poGDS->oHeader.element_size() + sComponentOffset;
     745            1600 :         memcpy( (void *) pDst, (void *) pSrc, sComponentSize );
     746                 :     }
     747                 : 
     748                 :     // Write the block that conatins all bands at once
     749              80 :     if( poGDS->WriteBlock( ) != CE_None )
     750                 :     {
     751               0 :         return CE_Failure;
     752                 :     }
     753                 : 
     754              80 :     return CE_None;
     755                 : }
     756                 : 
     757                 : /************************************************************************/
     758                 : /* ==================================================================== */
     759                 : /*                              GTADataset                              */
     760                 : /* ==================================================================== */
     761                 : /************************************************************************/
     762                 : 
     763                 : /************************************************************************/
     764                 : /*                            GTADataset()                              */
     765                 : /************************************************************************/
     766                 : 
     767             204 : GTADataset::GTADataset()
     768                 : 
     769                 : {
     770                 :     // Initialize Metadata
     771             204 :     bHaveGeoTransform = false;
     772             204 :     nGCPs = 0;
     773             204 :     pszGCPProjection = NULL;
     774             204 :     pasGCPs = NULL;
     775                 :     // Initialize block-based input/output
     776             204 :     nLastBlockXOff = -1;
     777             204 :     nLastBlockYOff = -1;
     778             204 :     pBlock = NULL;
     779             204 : }
     780                 : 
     781                 : /************************************************************************/
     782                 : /*                            ~GTADataset()                             */
     783                 : /************************************************************************/
     784                 : 
     785             204 : GTADataset::~GTADataset()
     786                 : 
     787                 : {
     788             204 :     FlushCache();
     789             204 :     VSIFree( pszGCPProjection );
     790             228 :     for( int i = 0; i < nGCPs; i++ )
     791                 :     {
     792              24 :         VSIFree( pasGCPs[i].pszId );
     793              24 :         VSIFree( pasGCPs[i].pszInfo );
     794                 :     }
     795             204 :     VSIFree( pasGCPs );
     796             204 :     VSIFree( pBlock );
     797             204 : }
     798                 : 
     799                 : /************************************************************************/
     800                 : /*                             ReadBlock()                              */
     801                 : /************************************************************************/
     802                 : 
     803            1320 : CPLErr GTADataset::ReadBlock( int nBlockXOff, int nBlockYOff )
     804                 : 
     805                 : {
     806                 :     /* Compressed data sets must be read into memory completely.
     807                 :      * Uncompressed data sets are read block-wise. */
     808                 : 
     809            1320 :     if( oHeader.compression() != gta::none )
     810                 :     {
     811               0 :         if( pBlock == NULL )
     812                 :         {
     813               0 :             if( oHeader.data_size() > (size_t)(-1)
     814                 :                     || ( pBlock = VSIMalloc( oHeader.data_size() ) ) == NULL )
     815                 :             {
     816                 :                 CPLError( CE_Failure, CPLE_OutOfMemory,
     817                 :                         "Cannot allocate buffer for the complete data set.\n"
     818                 :                         "Try to uncompress the data set to allow block-wise "
     819               0 :                         "reading.\n" );
     820               0 :                 return CE_Failure;
     821                 :             }
     822                 : 
     823                 :             try
     824                 :             {
     825               0 :                 oHeader.read_data( oGTAIO, pBlock );
     826                 :             }
     827               0 :             catch( gta::exception &e )
     828                 :             {
     829               0 :                 CPLError( CE_Failure, CPLE_FileIO, "GTA error: %s\n", e.what() );
     830               0 :                 return CE_Failure;
     831                 :             }
     832                 :         }
     833                 :     }
     834                 :     else
     835                 :     {
     836                 :         // This has to be the same as in the RasterBand constructor!
     837            1320 :         int nBlockXSize = GetRasterXSize();
     838            1320 :         int nBlockYSize = 1;
     839                 : 
     840            1320 :         if( nLastBlockXOff == nBlockXOff && nLastBlockYOff == nBlockYOff )
     841               0 :             return CE_None;
     842                 : 
     843            1320 :         if( pBlock == NULL )
     844                 :         {
     845              60 :             pBlock = VSIMalloc2( oHeader.element_size(), nBlockXSize );
     846              60 :             if( pBlock == NULL )
     847                 :             {
     848                 :                 CPLError( CE_Failure, CPLE_OutOfMemory,
     849               0 :                         "Cannot allocate scanline buffer" );
     850               0 :                 return CE_Failure;
     851                 :             }
     852                 :         }
     853                 : 
     854                 :         try
     855                 :         {
     856            1320 :             uintmax_t lo[2] = { nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize};
     857            1320 :             uintmax_t hi[2] = { lo[0] + nBlockXSize - 1, lo[1] + nBlockYSize - 1 };
     858            1320 :             oHeader.read_block( oGTAIO, DataOffset, lo, hi, pBlock );
     859                 :         }
     860               0 :         catch( gta::exception &e )
     861                 :         {
     862               0 :             CPLError( CE_Failure, CPLE_FileIO, "GTA error: %s\n", e.what() );
     863               0 :             return CE_Failure;
     864                 :         }
     865                 : 
     866            1320 :         nLastBlockXOff = nBlockXOff;
     867            1320 :         nLastBlockYOff = nBlockYOff;
     868                 :     }
     869            1320 :     return CE_None;
     870                 : }
     871                 : 
     872                 : /************************************************************************/
     873                 : /*                             WriteBlock()                             */
     874                 : /************************************************************************/
     875                 : 
     876              80 : CPLErr GTADataset::WriteBlock( )
     877                 : 
     878                 : {
     879                 :     // This has to be the same as in the RasterBand constructor!
     880              80 :     int nBlockXSize = GetRasterXSize();
     881              80 :     int nBlockYSize = 1;
     882                 : 
     883                 :     // Write the block (nLastBlockXOff, nLastBlockYOff) stored in pBlock.
     884                 :     try
     885                 :     {
     886              80 :         uintmax_t lo[2] = { nLastBlockXOff * nBlockXSize, nLastBlockYOff * nBlockYSize};
     887              80 :         uintmax_t hi[2] = { lo[0] + nBlockXSize - 1, lo[1] + nBlockYSize - 1 };
     888              80 :         oHeader.write_block( oGTAIO, DataOffset, lo, hi, pBlock );
     889                 :     }
     890               0 :     catch( gta::exception &e )
     891                 :     {
     892               0 :         CPLError( CE_Failure, CPLE_FileIO, "GTA error: %s\n", e.what() );
     893               0 :         return CE_Failure;
     894                 :     }
     895                 : 
     896              80 :     return CE_None;
     897                 : }
     898                 : 
     899                 : /************************************************************************/
     900                 : /*                          GetGeoTransform()                           */
     901                 : /************************************************************************/
     902                 : 
     903              84 : CPLErr GTADataset::GetGeoTransform( double * padfTransform )
     904                 : 
     905                 : {
     906              84 :     if( bHaveGeoTransform )
     907                 :     {
     908              82 :         memcpy( padfTransform, adfGeoTransform, 6*sizeof(double) );
     909              82 :         return CE_None;
     910                 :     }
     911                 :     else
     912                 :     {
     913               2 :         return CE_Failure;
     914                 :     }
     915                 : }
     916                 : 
     917                 : /************************************************************************/
     918                 : /*                          SetGeoTransform()                           */
     919                 : /************************************************************************/
     920                 : 
     921               0 : CPLErr GTADataset::SetGeoTransform( double * )
     922                 : 
     923                 : {
     924                 :     CPLError( CE_Warning, CPLE_NotSupported,
     925               0 :             "The GTA driver does not support metadata updates.\n" );
     926               0 :     return CE_Failure;
     927                 : }
     928                 : 
     929                 : /************************************************************************/
     930                 : /*                          GetProjectionRef()                          */
     931                 : /************************************************************************/
     932                 : 
     933             164 : const char *GTADataset::GetProjectionRef()
     934                 : 
     935                 : {
     936             164 :     const char *p = oHeader.global_taglist().get("GDAL/PROJECTION");
     937             164 :     return ( p ? p : "" );
     938                 : }
     939                 : 
     940                 : /************************************************************************/
     941                 : /*                          SetProjection()                             */
     942                 : /************************************************************************/
     943                 : 
     944               0 : CPLErr GTADataset::SetProjection( const char * )
     945                 : 
     946                 : {
     947                 :     CPLError( CE_Warning, CPLE_NotSupported,
     948               0 :             "The GTA driver does not support metadata updates.\n" );
     949               0 :     return CE_Failure;
     950                 : }
     951                 : 
     952                 : /************************************************************************/
     953                 : /*                          GetGCPCount()                               */
     954                 : /************************************************************************/
     955                 : 
     956               4 : int GTADataset::GetGCPCount( )
     957                 : 
     958                 : {
     959               4 :     return nGCPs;
     960                 : }
     961                 : 
     962                 : /************************************************************************/
     963                 : /*                          GetGCPProjection()                          */
     964                 : /************************************************************************/
     965                 : 
     966               2 : const char * GTADataset::GetGCPProjection( )
     967                 : 
     968                 : {
     969               2 :     return pszGCPProjection ? pszGCPProjection : "";
     970                 : }
     971                 : 
     972                 : /************************************************************************/
     973                 : /*                          GetGCPs()                                   */
     974                 : /************************************************************************/
     975                 : 
     976               2 : const GDAL_GCP * GTADataset::GetGCPs( )
     977                 : 
     978                 : {
     979               2 :     return pasGCPs;
     980                 : }
     981                 : 
     982                 : /************************************************************************/
     983                 : /*                          SetGCPs()                                   */
     984                 : /************************************************************************/
     985                 : 
     986               0 : CPLErr GTADataset::SetGCPs( int, const GDAL_GCP *, const char * )
     987                 : 
     988                 : {
     989                 :     CPLError( CE_Warning, CPLE_NotSupported,
     990               0 :             "The GTA driver does not support metadata updates.\n" );
     991               0 :     return CE_Failure;
     992                 : }
     993                 : 
     994                 : /************************************************************************/
     995                 : /*                                Open()                                */
     996                 : /************************************************************************/
     997                 : 
     998           26436 : GDALDataset *GTADataset::Open( GDALOpenInfo * poOpenInfo )
     999                 : 
    1000                 : {
    1001           26436 :     if( poOpenInfo->nHeaderBytes < 5 )
    1002           22488 :         return NULL;
    1003                 : 
    1004            3948 :     if( !EQUALN((char *)poOpenInfo->pabyHeader,"GTA",3) )
    1005            3744 :         return NULL;
    1006                 : 
    1007                 : /* -------------------------------------------------------------------- */
    1008                 : /*      Create a corresponding GDALDataset.                             */
    1009                 : /* -------------------------------------------------------------------- */
    1010                 :     GTADataset  *poDS;
    1011                 : 
    1012             204 :     poDS = new GTADataset();
    1013                 : 
    1014             268 :     if( poDS->oGTAIO.open( poOpenInfo->pszFilename,
    1015                 :             poOpenInfo->eAccess == GA_Update ? "r+" : "r" ) != 0 )
    1016                 :     {
    1017               0 :         CPLError( CE_Failure, CPLE_OpenFailed, "Cannot open file.\n" );
    1018               0 :         delete poDS;
    1019               0 :         return NULL;
    1020                 :     }
    1021                 : 
    1022                 : /* -------------------------------------------------------------------- */
    1023                 : /*      Read the header.                                                */
    1024                 : /* -------------------------------------------------------------------- */
    1025                 : 
    1026                 :     try
    1027                 :     {
    1028             204 :         poDS->oHeader.read_from( poDS->oGTAIO );
    1029                 :     }
    1030               0 :     catch( gta::exception &e )
    1031                 :     {
    1032               0 :         CPLError( CE_Failure, CPLE_OpenFailed, "GTA error: %s\n", e.what() );
    1033               0 :         delete poDS;
    1034               0 :         return NULL;
    1035                 :     }
    1036             204 :     poDS->DataOffset = poDS->oGTAIO.tell();
    1037             204 :     poDS->eAccess = poOpenInfo->eAccess;
    1038                 : 
    1039             274 :     if( poDS->oHeader.compression() != gta::none
    1040                 :             && poOpenInfo->eAccess == GA_Update )
    1041                 :     {
    1042                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1043                 :                   "The GTA driver does not support update access to compressed "
    1044               0 :                   "data sets.\nUncompress the data set first.\n" );
    1045               0 :         delete poDS;
    1046               0 :         return NULL;
    1047                 :     }
    1048                 : 
    1049             204 :     if( poDS->oHeader.dimensions() != 2 )
    1050                 :     {
    1051                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1052                 :                 "The GTA driver does not support GTAs with %s than 2 "
    1053                 :                 "dimensions.\n",
    1054               0 :                 poDS->oHeader.dimensions() < 2 ? "less" : "more" );
    1055               0 :         delete poDS;
    1056               0 :         return NULL;
    1057                 :     }
    1058                 : 
    1059                 :     // We know the dimensions are > 0 (guaranteed by libgta), but they may be
    1060                 :     // unrepresentable in GDAL.
    1061             204 :     if( poDS->oHeader.dimension_size(0) > INT_MAX
    1062                 :             || poDS->oHeader.dimension_size(1) > INT_MAX )
    1063                 :     {
    1064                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1065               0 :                 "The GTA driver does not support the size of this data set.\n" );
    1066               0 :         delete poDS;
    1067               0 :         return NULL;
    1068                 :     }
    1069             204 :     poDS->nRasterXSize = poDS->oHeader.dimension_size(0);
    1070             204 :     poDS->nRasterYSize = poDS->oHeader.dimension_size(1);
    1071                 : 
    1072                 :     // Check the number of bands (called components in GTA)
    1073             204 :     if( poDS->oHeader.components() > INT_MAX-1
    1074                 :             || poDS->oHeader.element_size() > ((size_t)-1) )
    1075                 :     {
    1076                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1077                 :                 "The GTA driver does not support the number or size of bands "
    1078               0 :                 "in this data set.\n" );
    1079               0 :         delete poDS;
    1080               0 :         return NULL;
    1081                 :     }
    1082             204 :     poDS->nBands = poDS->oHeader.components();
    1083                 : 
    1084                 :     // Check the data types (called component types in GTA)
    1085             536 :     for( int iBand = 0; iBand < poDS->nBands; iBand++ )
    1086                 :     {
    1087             332 :         if( poDS->oHeader.component_type(iBand) != gta::uint8
    1088                 :                 && poDS->oHeader.component_type(iBand) != gta::int8
    1089                 :                 && poDS->oHeader.component_type(iBand) != gta::uint16
    1090                 :                 && poDS->oHeader.component_type(iBand) != gta::int16
    1091                 :                 && poDS->oHeader.component_type(iBand) != gta::uint32
    1092                 :                 && poDS->oHeader.component_type(iBand) != gta::int32
    1093                 :                 && poDS->oHeader.component_type(iBand) != gta::float32
    1094                 :                 && poDS->oHeader.component_type(iBand) != gta::float64
    1095                 :                 && poDS->oHeader.component_type(iBand) != gta::cfloat32
    1096                 :                 && poDS->oHeader.component_type(iBand) != gta::cfloat64 )
    1097                 :         {
    1098                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1099                 :                     "The GTA driver does not support some of the data types "
    1100               0 :                     "used in this data set.\n" );
    1101               0 :             delete poDS;
    1102               0 :             return NULL;
    1103                 :         }
    1104                 :     }
    1105                 : 
    1106                 : /* -------------------------------------------------------------------- */
    1107                 : /*      Read and set meta information.                                  */
    1108                 : /* -------------------------------------------------------------------- */
    1109                 : 
    1110             204 :     if( poDS->oHeader.global_taglist().get("GDAL/GEO_TRANSFORM") )
    1111                 :     {
    1112             192 :         poDS->bHaveGeoTransform = true;
    1113                 :         ScanDoubles( poDS->oHeader.global_taglist().get( "GDAL/GEO_TRANSFORM" ),
    1114             192 :                 poDS->adfGeoTransform, 6 );
    1115                 :     }
    1116                 :     else
    1117                 :     {
    1118              12 :         poDS->bHaveGeoTransform = false;
    1119                 :     }
    1120                 : 
    1121             204 :     if( poDS->oHeader.global_taglist().get("GDAL/GCP_PROJECTION") )
    1122                 :     {
    1123               6 :         poDS->pszGCPProjection = VSIStrdup( poDS->oHeader.global_taglist().get("GDAL/GCP_PROJECTION") );
    1124                 :     }
    1125             204 :     if( poDS->oHeader.global_taglist().get("GDAL/GCP_COUNT") )
    1126                 :     {
    1127               6 :         poDS->nGCPs = atoi( poDS->oHeader.global_taglist().get("GDAL/GCP_COUNT") );
    1128               6 :         if( poDS->nGCPs < 1 )
    1129                 :         {
    1130               0 :             poDS->nGCPs = 0;
    1131                 :         }
    1132                 :         else
    1133                 :         {
    1134               6 :             poDS->pasGCPs = (GDAL_GCP *)VSIMalloc2( poDS->nGCPs, sizeof(GDAL_GCP) );
    1135               6 :             if( poDS->pasGCPs == NULL )
    1136                 :             {
    1137               0 :                 CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate GCP list" );
    1138               0 :                 delete poDS;
    1139               0 :                 return NULL;
    1140                 :             }
    1141              30 :             for( int i = 0; i < poDS->nGCPs; i++ )
    1142                 :             {
    1143              24 :                 poDS->pasGCPs[i].pszInfo = NULL;
    1144              24 :                 poDS->pasGCPs[i].dfGCPPixel = 0.0;
    1145              24 :                 poDS->pasGCPs[i].dfGCPLine = 0.0;
    1146              24 :                 poDS->pasGCPs[i].dfGCPX = 0.0;
    1147              24 :                 poDS->pasGCPs[i].dfGCPY = 0.0;
    1148              24 :                 poDS->pasGCPs[i].dfGCPZ = 0.0;
    1149              24 :                 poDS->pasGCPs[i].pszId = VSIStrdup( CPLSPrintf( "%d", i ) );
    1150                 :                 char pszGCPTagName[64];
    1151                 :                 char pszGCPInfoTagName[64];
    1152              24 :                 strcpy( pszGCPTagName, CPLSPrintf( "GDAL/GCP%d", i ) );
    1153              24 :                 strcpy( pszGCPInfoTagName, CPLSPrintf( "GDAL/GCP%d_INFO", i ) );
    1154              24 :                 if( poDS->oHeader.global_taglist().get(pszGCPInfoTagName) )
    1155                 :                 {
    1156               0 :                     poDS->pasGCPs[i].pszInfo = VSIStrdup( poDS->oHeader.global_taglist().get(pszGCPInfoTagName) );
    1157                 :                 }
    1158                 :                 else
    1159                 :                 {
    1160              24 :                     poDS->pasGCPs[i].pszInfo = VSIStrdup( "" );
    1161                 :                 }
    1162              24 :                 if( poDS->oHeader.global_taglist().get(pszGCPTagName) )
    1163                 :                 {
    1164                 :                     double adfTempDoubles[5];
    1165              24 :                     ScanDoubles( poDS->oHeader.global_taglist().get(pszGCPTagName), adfTempDoubles, 5 );
    1166              24 :                     poDS->pasGCPs[i].dfGCPPixel = adfTempDoubles[0];
    1167              24 :                     poDS->pasGCPs[i].dfGCPLine = adfTempDoubles[1];
    1168              24 :                     poDS->pasGCPs[i].dfGCPX = adfTempDoubles[2];
    1169              24 :                     poDS->pasGCPs[i].dfGCPY = adfTempDoubles[3];
    1170              24 :                     poDS->pasGCPs[i].dfGCPZ = adfTempDoubles[4];
    1171                 :                 }
    1172                 :             }
    1173                 :         }
    1174                 :     }
    1175                 : 
    1176             204 :     if( poDS->oHeader.global_taglist().get("DESCRIPTION") )
    1177                 :     {
    1178             198 :         poDS->SetDescription( poDS->oHeader.global_taglist().get("DESCRIPTION") );
    1179                 :     }
    1180             996 :     for( uintmax_t i = 0; i < poDS->oHeader.global_taglist().tags(); i++)
    1181                 :     {
    1182             792 :         const char *pszTagName = poDS->oHeader.global_taglist().name( i );
    1183             792 :         if( strncmp( pszTagName, "GDAL/META/", 10 ) == 0 )
    1184                 :         {
    1185             174 :             const char *pDomainEnd = strchr( pszTagName + 10, '/' );
    1186             174 :             if( pDomainEnd && pDomainEnd - (pszTagName + 10) > 0 )
    1187                 :             {
    1188             174 :                 char *pszDomain = (char *)VSIMalloc( pDomainEnd - (pszTagName + 10) + 1 );
    1189             174 :                 if( !pszDomain )
    1190                 :                 {
    1191               0 :                     CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate metadata buffer" );
    1192               0 :                     delete poDS;
    1193               0 :                     return NULL;
    1194                 :                 }
    1195                 :                 int j;
    1196            1392 :                 for( j = 0; j < pDomainEnd - (pszTagName + 10); j++ )
    1197                 :                 {
    1198            1218 :                     pszDomain[j] = pszTagName[10 + j];
    1199                 :                 }
    1200             174 :                 pszDomain[j] = '\0';
    1201             174 :                 const char *pszName = pszTagName + 10 + j + 1;
    1202             174 :                 const char *pszValue = poDS->oHeader.global_taglist().value( i );
    1203                 :                 poDS->SetMetadataItem( pszName, pszValue,
    1204             174 :                         strcmp( pszDomain, "DEFAULT" ) == 0 ? NULL : pszDomain );
    1205             174 :                 VSIFree( pszDomain );
    1206                 :             }
    1207                 :         }
    1208                 :     }
    1209                 : 
    1210             204 :     if( poDS->nBands > 0 )
    1211                 :     {
    1212             204 :         poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    1213                 :     }
    1214             204 :     if( poDS->oHeader.compression() == gta::bzip2 )
    1215               6 :         poDS->SetMetadataItem( "COMPRESSION", "BZIP2", "IMAGE_STRUCTURE" );
    1216             198 :     else if( poDS->oHeader.compression() == gta::xz )
    1217               6 :         poDS->SetMetadataItem( "COMPRESSION", "XZ", "IMAGE_STRUCTURE" );
    1218             192 :     else if( poDS->oHeader.compression() == gta::zlib )
    1219               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB", "IMAGE_STRUCTURE" );
    1220             186 :     else if( poDS->oHeader.compression() == gta::zlib1 )
    1221               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB1", "IMAGE_STRUCTURE" );
    1222             180 :     else if( poDS->oHeader.compression() == gta::zlib2 )
    1223               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB2", "IMAGE_STRUCTURE" );
    1224             174 :     else if( poDS->oHeader.compression() == gta::zlib3 )
    1225               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB3", "IMAGE_STRUCTURE" );
    1226             168 :     else if( poDS->oHeader.compression() == gta::zlib4 )
    1227               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB4", "IMAGE_STRUCTURE" );
    1228             162 :     else if( poDS->oHeader.compression() == gta::zlib5 )
    1229               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB5", "IMAGE_STRUCTURE" );
    1230             156 :     else if( poDS->oHeader.compression() == gta::zlib6 )
    1231               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB6", "IMAGE_STRUCTURE" );
    1232             150 :     else if( poDS->oHeader.compression() == gta::zlib7 )
    1233               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB7", "IMAGE_STRUCTURE" );
    1234             144 :     else if( poDS->oHeader.compression() == gta::zlib8 )
    1235               6 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB8", "IMAGE_STRUCTURE" );
    1236             138 :     else if( poDS->oHeader.compression() == gta::zlib9 )
    1237               4 :         poDS->SetMetadataItem( "COMPRESSION", "ZLIB9", "IMAGE_STRUCTURE" );
    1238                 : 
    1239                 : /* -------------------------------------------------------------------- */
    1240                 : /*      Create band information objects.                                */
    1241                 : /* -------------------------------------------------------------------- */
    1242            1072 :     for( int iBand = 0; iBand < poDS->nBands; iBand++ )
    1243                 :     {
    1244             332 :         poDS->SetBand( iBand+1, new GTARasterBand( poDS, iBand+1 ) );
    1245                 :     }
    1246                 : 
    1247                 : /* -------------------------------------------------------------------- */
    1248                 : /*      Initialize any PAM information.                                 */
    1249                 : /* -------------------------------------------------------------------- */
    1250             204 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1251             204 :     poDS->TryLoadXML();
    1252                 : 
    1253                 : /* -------------------------------------------------------------------- */
    1254                 : /*      Check for overviews.                                            */
    1255                 : /* -------------------------------------------------------------------- */
    1256             204 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    1257                 : 
    1258             204 :     return( poDS );
    1259                 : }
    1260                 : 
    1261                 : /************************************************************************/
    1262                 : /*                             CreateCopy()                             */
    1263                 : /************************************************************************/
    1264                 : 
    1265                 : static GDALDataset*
    1266              94 : GTACreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
    1267                 :                 int bStrict, char ** papszOptions,
    1268                 :                 GDALProgressFunc pfnProgress, void * pProgressData )
    1269                 : 
    1270                 : {
    1271              94 :     if( !pfnProgress( 0.0, NULL, pProgressData ) )
    1272               0 :         return NULL;
    1273                 : 
    1274                 : /* -------------------------------------------------------------------- */
    1275                 : /*      Create a GTA header                                             */
    1276                 : /* -------------------------------------------------------------------- */
    1277                 : 
    1278              94 :     gta::compression eGTACompression = gta::none;
    1279                 :     const char *pszCompressionValue = CSLFetchNameValue( papszOptions,
    1280              94 :             "COMPRESS" );
    1281              94 :     if( pszCompressionValue != NULL )
    1282                 :     {
    1283              26 :         if( EQUAL( pszCompressionValue, "NONE" ) )
    1284               2 :             eGTACompression = gta::none;
    1285              24 :         else if( EQUAL( pszCompressionValue, "BZIP2" ) )
    1286               2 :             eGTACompression = gta::bzip2;
    1287              22 :         else if( EQUAL( pszCompressionValue, "XZ" ) )
    1288               2 :             eGTACompression = gta::xz;
    1289              20 :         else if( EQUAL( pszCompressionValue, "ZLIB" ))
    1290               2 :             eGTACompression = gta::zlib;
    1291              18 :         else if( EQUAL( pszCompressionValue, "ZLIB1" ))
    1292               2 :             eGTACompression = gta::zlib1;
    1293              16 :         else if( EQUAL( pszCompressionValue, "ZLIB2" ))
    1294               2 :             eGTACompression = gta::zlib2;
    1295              14 :         else if( EQUAL( pszCompressionValue, "ZLIB3" ))
    1296               2 :             eGTACompression = gta::zlib3;
    1297              12 :         else if( EQUAL( pszCompressionValue, "ZLIB4" ))
    1298               2 :             eGTACompression = gta::zlib4;
    1299              10 :         else if( EQUAL( pszCompressionValue, "ZLIB5" ))
    1300               2 :             eGTACompression = gta::zlib5;
    1301               8 :         else if( EQUAL( pszCompressionValue, "ZLIB6" ))
    1302               2 :             eGTACompression = gta::zlib6;
    1303               6 :         else if( EQUAL( pszCompressionValue, "ZLIB7" ))
    1304               2 :             eGTACompression = gta::zlib7;
    1305               4 :         else if( EQUAL( pszCompressionValue, "ZLIB8" ))
    1306               2 :             eGTACompression = gta::zlib8;
    1307               2 :         else if( EQUAL( pszCompressionValue, "ZLIB9" ))
    1308               2 :             eGTACompression = gta::zlib9;
    1309                 :         else
    1310                 :             CPLError( CE_Warning, CPLE_IllegalArg,
    1311                 :                       "COMPRESS=%s value not recognised, ignoring.",
    1312               0 :                       pszCompressionValue );
    1313                 :     }
    1314                 : 
    1315              94 :     gta::type *peGTATypes = (gta::type *)VSIMalloc2( poSrcDS->GetRasterCount(), sizeof(gta::type) );
    1316              94 :     if( peGTATypes == NULL )
    1317                 :     {
    1318               2 :         CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate GTA type list" );
    1319               2 :         return NULL;
    1320                 :     }
    1321             236 :     for( int i = 0; i < poSrcDS->GetRasterCount(); i++ )
    1322                 :     {
    1323             148 :         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( i+1 );
    1324             148 :         if( poSrcBand->GetColorInterpretation() == GCI_PaletteIndex )
    1325                 :         {
    1326                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1327               0 :                     "The GTA driver does not support color palettes.\n" );
    1328               0 :             VSIFree( peGTATypes );
    1329               0 :             return NULL;
    1330                 :         }
    1331             148 :         GDALDataType eDT = poSrcBand->GetRasterDataType();
    1332             148 :         switch( eDT )
    1333                 :         {
    1334                 :         case GDT_Byte:
    1335                 :         {
    1336             108 :             const char *pszPixelType = poSrcBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    1337             110 :             if (pszPixelType && EQUAL(pszPixelType, "SIGNEDBYTE"))
    1338               2 :                 peGTATypes[i] = gta::int8;
    1339                 :             else
    1340             106 :                 peGTATypes[i] = gta::uint8;
    1341             108 :             break;
    1342                 :         }
    1343                 :         case GDT_UInt16:
    1344               4 :             peGTATypes[i] = gta::uint16;
    1345               4 :             break;
    1346                 :         case GDT_Int16:
    1347               4 :             peGTATypes[i] = gta::int16;
    1348               4 :             break;
    1349                 :         case GDT_UInt32:
    1350               4 :             peGTATypes[i] = gta::uint32;
    1351               4 :             break;
    1352                 :         case GDT_Int32:
    1353               4 :             peGTATypes[i] = gta::int32;
    1354               4 :             break;
    1355                 :         case GDT_Float32:
    1356               4 :             peGTATypes[i] = gta::float32;
    1357               4 :             break;
    1358                 :         case GDT_Float64:
    1359               4 :             peGTATypes[i] = gta::float64;
    1360               4 :             break;
    1361                 :         case GDT_CInt16:
    1362               4 :             if( bStrict )
    1363                 :             {
    1364                 :                 CPLError( CE_Failure, CPLE_NotSupported,
    1365                 :                         "The GTA driver does not support the CInt16 data "
    1366                 :                         "type.\n"
    1367                 :                         "(If no strict copy is required, the driver can "
    1368               2 :                         "use CFloat32 instead.)\n" );
    1369               2 :                 VSIFree( peGTATypes );
    1370               2 :                 return NULL;
    1371                 :             }
    1372               2 :             peGTATypes[i] = gta::cfloat32;
    1373               2 :             break;
    1374                 :         case GDT_CInt32:
    1375               4 :             if( bStrict )
    1376                 :             {
    1377                 :                 CPLError( CE_Failure, CPLE_NotSupported,
    1378                 :                         "The GTA driver does not support the CInt32 data "
    1379                 :                         "type.\n"
    1380                 :                         "(If no strict copy is required, the driver can "
    1381               2 :                         "use CFloat64 instead.)\n" );
    1382               2 :                 VSIFree( peGTATypes );
    1383               2 :                 return NULL;
    1384                 :             }
    1385               2 :             peGTATypes[i] = gta::cfloat64;
    1386               2 :             break;
    1387                 :         case GDT_CFloat32:
    1388               4 :             peGTATypes[i] = gta::cfloat32;
    1389               4 :             break;
    1390                 :         case GDT_CFloat64:
    1391               4 :             peGTATypes[i] = gta::cfloat64;
    1392               4 :             break;
    1393                 :         default:
    1394                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1395                 :                     "The GTA driver does not support source data sets using "
    1396               0 :                     "unknown data types.\n");
    1397               0 :             VSIFree( peGTATypes );
    1398               0 :             return NULL;
    1399                 :         }
    1400                 :     }
    1401                 : 
    1402              88 :     gta::header oHeader;
    1403                 :     try
    1404                 :     {
    1405              88 :         oHeader.set_compression( eGTACompression );
    1406              88 :         oHeader.set_dimensions( poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize() );
    1407              88 :         oHeader.set_components( poSrcDS->GetRasterCount(), peGTATypes );
    1408              88 :         const char *pszDescription = poSrcDS->GetDescription();
    1409                 :         // Metadata from GDALMajorObject
    1410              88 :         if( pszDescription && pszDescription[0] != '\0' )
    1411                 :         {
    1412              86 :             oHeader.global_taglist().set( "DESCRIPTION", pszDescription );
    1413                 :         }
    1414              88 :         const char *papszMetadataDomains[] = { NULL /* default */, "RPC" };
    1415              88 :         size_t nMetadataDomains = sizeof( papszMetadataDomains ) / sizeof( papszMetadataDomains[0] );
    1416             264 :         for( size_t iDomain = 0; iDomain < nMetadataDomains; iDomain++ )
    1417                 :         {
    1418             176 :             char **papszMetadata = poSrcDS->GetMetadata( papszMetadataDomains[iDomain] );
    1419             176 :             if( papszMetadata )
    1420                 :             {
    1421             152 :                 for( int i = 0; papszMetadata[i]; i++ )
    1422                 :                 {
    1423              76 :                     char *pEqualSign = strchr( papszMetadata[i], '=' );
    1424              76 :                     if( pEqualSign && pEqualSign - papszMetadata[i] > 0 )
    1425                 :                     {
    1426              76 :                         *pEqualSign = '\0';
    1427                 :                         oHeader.global_taglist().set(
    1428                 :                                 CPLSPrintf( "GDAL/META/%s/%s",
    1429              76 :                                     papszMetadataDomains[iDomain] ? papszMetadataDomains[iDomain] : "DEFAULT",
    1430                 :                                     papszMetadata[i] ),
    1431             152 :                                 pEqualSign + 1 );
    1432              76 :                         *pEqualSign = '=';
    1433                 :                     }
    1434                 :                 }
    1435                 :             }
    1436                 :         }
    1437                 :         // Projection and transformation
    1438              88 :         const char *pszWKT = poSrcDS->GetProjectionRef();
    1439              88 :         if( pszWKT && pszWKT[0] != '\0' )
    1440                 :         {
    1441              84 :             oHeader.global_taglist().set( "GDAL/PROJECTION", pszWKT );
    1442                 :         }
    1443                 :         double adfTransform[6];
    1444              88 :         if( poSrcDS->GetGeoTransform( adfTransform ) == CE_None )
    1445                 :         {
    1446                 :             oHeader.global_taglist().set( "GDAL/GEO_TRANSFORM",
    1447              84 :                     PrintDoubles( adfTransform, 6 ).c_str() );
    1448                 :         }
    1449                 :         // GCPs
    1450              88 :         if( poSrcDS->GetGCPCount() > 0 )
    1451                 :         {
    1452               2 :             oHeader.global_taglist().set( "GDAL/GCP_COUNT", CPLSPrintf( "%d", poSrcDS->GetGCPCount() ) );
    1453               2 :             oHeader.global_taglist().set( "GDAL/GCP_PROJECTION", poSrcDS->GetGCPProjection() );
    1454               2 :             const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
    1455              10 :             for( int i = 0; i < poSrcDS->GetGCPCount(); i++ )
    1456                 :             {
    1457                 :                 char pszGCPTagName[64];
    1458                 :                 char pszGCPInfoTagName[64];
    1459               8 :                 strcpy( pszGCPTagName, CPLSPrintf( "GDAL/GCP%d", i ) );
    1460               8 :                 strcpy( pszGCPInfoTagName, CPLSPrintf( "GDAL/GCP%d_INFO", i ) );
    1461               8 :                 if( pasGCPs[i].pszInfo && pasGCPs[i].pszInfo[0] != '\0' )
    1462                 :                 {
    1463               0 :                     oHeader.global_taglist().set( pszGCPInfoTagName, pasGCPs[i].pszInfo );
    1464                 :                 }
    1465                 :                 double adfTempDoubles[5];
    1466               8 :                 adfTempDoubles[0] = pasGCPs[i].dfGCPPixel;
    1467               8 :                 adfTempDoubles[1] = pasGCPs[i].dfGCPLine;
    1468               8 :                 adfTempDoubles[2] = pasGCPs[i].dfGCPX;
    1469               8 :                 adfTempDoubles[3] = pasGCPs[i].dfGCPY;
    1470               8 :                 adfTempDoubles[4] = pasGCPs[i].dfGCPZ;
    1471               8 :                 oHeader.global_taglist().set( pszGCPTagName, PrintDoubles( adfTempDoubles, 5 ).c_str() );
    1472                 :             }
    1473                 :         }
    1474                 :         // Now the bands
    1475             232 :         for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
    1476                 :         {
    1477             144 :             GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
    1478                 :             // Metadata from GDALMajorObject
    1479             144 :             const char *pszBandDescription = poSrcBand->GetDescription();
    1480             144 :             if( pszBandDescription && pszBandDescription[0] != '\0' )
    1481                 :             {
    1482               2 :                 oHeader.component_taglist( iBand ).set( "DESCRIPTION", pszBandDescription );
    1483                 :             }
    1484             432 :             for( size_t iDomain = 0; iDomain < nMetadataDomains; iDomain++ )
    1485                 :             {
    1486             288 :                 char **papszBandMetadata = poSrcBand->GetMetadata( papszMetadataDomains[iDomain] );
    1487             288 :                 if( papszBandMetadata )
    1488                 :                 {
    1489              10 :                     for( int i = 0; papszBandMetadata[i]; i++ )
    1490                 :                     {
    1491               8 :                         char *pEqualSign = strchr( papszBandMetadata[i], '=' );
    1492               8 :                         if( pEqualSign && pEqualSign - papszBandMetadata[i] > 0 )
    1493                 :                         {
    1494               8 :                             *pEqualSign = '\0';
    1495                 :                             oHeader.component_taglist( iBand ).set(
    1496                 :                                     CPLSPrintf( "GDAL/META/%s/%s",
    1497               8 :                                         papszMetadataDomains[iDomain] ? papszMetadataDomains[iDomain] : "DEFAULT",
    1498                 :                                         papszBandMetadata[i] ),
    1499              16 :                                     pEqualSign + 1 );
    1500               8 :                             *pEqualSign = '=';
    1501                 :                         }
    1502                 :                     }
    1503                 :                 }
    1504                 :             }
    1505                 :             // Category names
    1506             144 :             char **papszCategoryNames = poSrcBand->GetCategoryNames( );
    1507             144 :             if( papszCategoryNames )
    1508                 :             {
    1509                 :                 int i;
    1510               6 :                 for( i = 0; papszCategoryNames[i]; i++ )
    1511                 :                 {
    1512                 :                     oHeader.component_taglist( iBand ).set(
    1513                 :                             CPLSPrintf( "GDAL/CATEGORY%d", i ),
    1514               4 :                             papszCategoryNames[i] );
    1515                 :                 }
    1516                 :                 oHeader.component_taglist( iBand ).set(
    1517               2 :                         "GDAL/CATEGORY_COUNT", CPLSPrintf( "%d", i ) );
    1518                 :             }
    1519                 :             // No data value
    1520                 :             int bHaveNoDataValue;
    1521                 :             double dfNoDataValue;
    1522             144 :             dfNoDataValue = poSrcBand->GetNoDataValue( &bHaveNoDataValue );
    1523             144 :             if( bHaveNoDataValue )
    1524                 :                 oHeader.component_taglist( iBand ).set( "NO_DATA_VALUE",
    1525               2 :                         PrintDoubles( &dfNoDataValue, 1 ).c_str() );
    1526                 :             // Min/max values
    1527                 :             int bHaveMinValue;
    1528                 :             double dfMinValue;
    1529             144 :             dfMinValue = poSrcBand->GetMinimum( &bHaveMinValue );
    1530             144 :             if( bHaveMinValue )
    1531                 :                 oHeader.component_taglist( iBand ).set( "MIN_VALUE",
    1532               2 :                         PrintDoubles( &dfMinValue, 1 ).c_str() );
    1533                 :             int bHaveMaxValue;
    1534                 :             double dfMaxValue;
    1535             144 :             dfMaxValue = poSrcBand->GetMaximum( &bHaveMaxValue );
    1536             144 :             if( bHaveMaxValue )
    1537                 :                 oHeader.component_taglist( iBand ).set( "MAX_VALUE",
    1538               2 :                         PrintDoubles( &dfMaxValue, 1 ).c_str() );
    1539                 :             // Offset/scale values
    1540                 :             int bHaveOffsetValue;
    1541                 :             double dfOffsetValue;
    1542             144 :             dfOffsetValue = poSrcBand->GetOffset( &bHaveOffsetValue );
    1543             144 :             if( bHaveOffsetValue )
    1544                 :                 oHeader.component_taglist( iBand ).set( "GDAL/OFFSET",
    1545             142 :                         PrintDoubles( &dfOffsetValue, 1 ).c_str() );
    1546                 :             int bHaveScaleValue;
    1547                 :             double dfScaleValue;
    1548             144 :             dfScaleValue = poSrcBand->GetScale( &bHaveScaleValue );
    1549             144 :             if( bHaveScaleValue )
    1550                 :                 oHeader.component_taglist( iBand ).set( "GDAL/SCALE",
    1551             142 :                         PrintDoubles( &dfScaleValue, 1 ).c_str() );
    1552                 :             // Unit
    1553             144 :             const char *pszUnit = poSrcBand->GetUnitType( );
    1554             144 :             if( pszUnit != NULL && pszUnit[0] != '\0' )
    1555               2 :                 oHeader.component_taglist( iBand ).set( "UNIT", pszUnit );
    1556                 :             // Color interpretation
    1557             144 :             GDALColorInterp eCI = poSrcBand->GetColorInterpretation();
    1558             144 :             if( eCI == GCI_GrayIndex )
    1559              82 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "GRAY" );
    1560              62 :             else if( eCI == GCI_RedBand )
    1561               8 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "RED" );
    1562              54 :             else if( eCI == GCI_GreenBand )
    1563               8 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "GREEN" );
    1564              46 :             else if( eCI == GCI_BlueBand )
    1565               8 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "BLUE" );
    1566              38 :             else if( eCI == GCI_AlphaBand )
    1567               4 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "ALPHA" );
    1568              34 :             else if( eCI == GCI_HueBand )
    1569               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/H" );
    1570              32 :             else if( eCI == GCI_SaturationBand )
    1571               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/S" );
    1572              30 :             else if( eCI == GCI_LightnessBand )
    1573               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "HSL/L" );
    1574              28 :             else if( eCI == GCI_CyanBand )
    1575               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/C" );
    1576              26 :             else if( eCI == GCI_MagentaBand )
    1577               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/M" );
    1578              24 :             else if( eCI == GCI_YellowBand )
    1579               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/Y" );
    1580              22 :             else if( eCI == GCI_BlackBand )
    1581               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "CMYK/K" );
    1582              20 :             else if( eCI == GCI_YCbCr_YBand )
    1583               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/Y" );
    1584              18 :             else if( eCI == GCI_YCbCr_CbBand )
    1585               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/CB" );
    1586              16 :             else if( eCI == GCI_YCbCr_CrBand )
    1587               2 :                 oHeader.component_taglist( iBand ).set( "INTERPRETATION", "YCBCR/CR" );
    1588                 :         }
    1589                 :     }
    1590               0 :     catch( gta::exception &e )
    1591                 :     {
    1592               0 :         CPLError( CE_Failure, CPLE_NotSupported, "GTA error: %s\n", e.what() );
    1593               0 :         VSIFree( peGTATypes );
    1594               0 :         return NULL;
    1595                 :     }
    1596              88 :     VSIFree( peGTATypes );
    1597                 : 
    1598                 : /* -------------------------------------------------------------------- */
    1599                 : /*      Write header and data to the file                               */
    1600                 : /* -------------------------------------------------------------------- */
    1601                 : 
    1602              88 :     GTAIO oGTAIO;
    1603              88 :     if( oGTAIO.open( pszFilename, "w" ) != 0 )
    1604                 :     {
    1605                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    1606               4 :                 "Cannot create GTA file %s.\n", pszFilename );
    1607               4 :         return NULL;
    1608                 :     }
    1609                 : 
    1610              84 :     void *pLine = VSIMalloc2( oHeader.element_size(), oHeader.dimension_size(0) );
    1611              84 :     if( pLine == NULL )
    1612                 :     {
    1613               0 :         CPLError( CE_Failure, CPLE_OutOfMemory, "Cannot allocate scanline buffer.\n" );
    1614               0 :         VSIFree( pLine );
    1615               0 :         return NULL;
    1616                 :     }
    1617                 : 
    1618                 :     try
    1619                 :     {
    1620                 :         // Write header
    1621              84 :         oHeader.write_to( oGTAIO );
    1622                 :         // Write data line by line
    1623              84 :         gta::io_state oGTAIOState;
    1624            1686 :         for( int iLine = 0; iLine < poSrcDS->GetRasterYSize(); iLine++ )
    1625                 :         {
    1626            1602 :             size_t nComponentOffset = 0;
    1627            3636 :             for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
    1628                 :             {
    1629            2034 :                 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
    1630            2034 :                 GDALDataType eDT = poSrcBand->GetRasterDataType();
    1631            2034 :                 if( eDT == GDT_CInt16 )
    1632                 :                 {
    1633              40 :                     eDT = GDT_CFloat32;
    1634                 :                 }
    1635            1994 :                 else if( eDT == GDT_CInt32 )
    1636                 :                 {
    1637              40 :                     eDT = GDT_CFloat64;
    1638                 :                 }
    1639            2034 :                 char *pDst = (char *)pLine + nComponentOffset;
    1640                 :                 CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, iLine,
    1641                 :                         poSrcDS->GetRasterXSize(), 1,
    1642                 :                         pDst, poSrcDS->GetRasterXSize(), 1, eDT,
    1643            2034 :                         oHeader.element_size(), 0 );
    1644            2034 :                 if( eErr != CE_None )
    1645                 :                 {
    1646               0 :                     CPLError( CE_Failure, CPLE_FileIO, "Cannot read source data set.\n" );
    1647               0 :                     VSIFree( pLine );
    1648               0 :                     return NULL;
    1649                 :                 }
    1650            2034 :                 nComponentOffset += oHeader.component_size( iBand );
    1651                 :             }
    1652            1602 :             oHeader.write_elements( oGTAIOState, oGTAIO, poSrcDS->GetRasterXSize(), pLine );
    1653            1602 :             if( !pfnProgress( (iLine+1) / (double) poSrcDS->GetRasterYSize(),
    1654                 :                         NULL, pProgressData ) )
    1655                 :             {
    1656               0 :                 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated CreateCopy()" );
    1657               0 :                 VSIFree( pLine );
    1658               0 :                 return NULL;
    1659                 :             }
    1660               0 :         }
    1661                 :     }
    1662               0 :     catch( gta::exception &e )
    1663                 :     {
    1664               0 :         CPLError( CE_Failure, CPLE_FileIO, "GTA write error: %s\n", e.what() );
    1665               0 :         VSIFree( pLine );
    1666               0 :         return NULL;
    1667                 :     }
    1668              84 :     VSIFree( pLine );
    1669                 : 
    1670              84 :     oGTAIO.close();
    1671                 : 
    1672                 : /* -------------------------------------------------------------------- */
    1673                 : /*      Re-open dataset, and copy any auxilary pam information.         */
    1674                 : /* -------------------------------------------------------------------- */
    1675                 : 
    1676                 :     GTADataset *poDS = (GTADataset *) GDALOpen( pszFilename,
    1677              84 :             eGTACompression == gta::none ? GA_Update : GA_ReadOnly );
    1678                 : 
    1679              84 :     if( poDS )
    1680              84 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    1681                 : 
    1682              84 :     return poDS;
    1683                 : }
    1684                 : 
    1685                 : /************************************************************************/
    1686                 : /*                          GDALRegister_GTA()                          */
    1687                 : /************************************************************************/
    1688                 : 
    1689            1135 : void GDALRegister_GTA()
    1690                 : 
    1691                 : {
    1692                 :     GDALDriver  *poDriver;
    1693                 : 
    1694            1135 :     if( GDALGetDriverByName( "GTA" ) == NULL )
    1695                 :     {
    1696            1093 :         poDriver = new GDALDriver();
    1697                 : 
    1698            1093 :         poDriver->SetDescription( "GTA" );
    1699                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    1700            1093 :                 "Generic Tagged Arrays (.gta)" );
    1701                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
    1702            1093 :                 "frmt_gta.html" );
    1703            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gta" );
    1704                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
    1705                 :                 "Byte UInt16 Int16 UInt32 Int32 Float32 Float64 "
    1706            1093 :                 "CInt16 CInt32 CFloat32 CFloat64" );
    1707                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    1708                 :                 "<CreationOptionList>"
    1709                 :                 "  <Option name='COMPRESS' type='string-select'>"
    1710                 :                 "    <Value>NONE</Value>"
    1711                 :                 "    <Value>BZIP2</Value>"
    1712                 :                 "    <Value>XZ</Value>"
    1713                 :                 "    <Value>ZLIB</Value>"
    1714                 :                 "    <Value>ZLIB1</Value>"
    1715                 :                 "    <Value>ZLIB2</Value>"
    1716                 :                 "    <Value>ZLIB3</Value>"
    1717                 :                 "    <Value>ZLIB4</Value>"
    1718                 :                 "    <Value>ZLIB5</Value>"
    1719                 :                 "    <Value>ZLIB6</Value>"
    1720                 :                 "    <Value>ZLIB7</Value>"
    1721                 :                 "    <Value>ZLIB8</Value>"
    1722                 :                 "    <Value>ZLIB9</Value>"
    1723                 :                 "  </Option>"
    1724            1093 :                 "</CreationOptionList>" );
    1725                 : 
    1726            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    1727                 : 
    1728            1093 :         poDriver->pfnOpen = GTADataset::Open;
    1729            1093 :         poDriver->pfnCreateCopy = GTACreateCopy;
    1730                 : 
    1731            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1732                 :     }
    1733            1135 : }

Generated by: LCOV version 1.7