LCOV - code coverage report
Current view: directory - frmts/mrsid - mrsiddataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1017 613 60.3 %
Date: 2012-12-26 Functions: 52 40 76.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: mrsiddataset.cpp 24375 2012-05-03 17:46:08Z rouault $
       3                 :  *
       4                 :  * Project:  Multi-resolution Seamless Image Database (MrSID)
       5                 :  * Purpose:  Read/write LizardTech's MrSID file format - Version 4+ SDK.
       6                 :  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
      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                 : #define NO_DELETE
      31                 : 
      32                 : #include "gdal_pam.h"
      33                 : #include "ogr_spatialref.h"
      34                 : #include "cpl_string.h"
      35                 : #include "gdaljp2metadata.h"
      36                 : #include <string>
      37                 : 
      38                 : #include <geo_normalize.h>
      39                 : #include <geovalues.h>
      40                 : 
      41                 : CPL_CVSID("$Id: mrsiddataset.cpp 24375 2012-05-03 17:46:08Z rouault $");
      42                 : 
      43                 : CPL_C_START
      44                 : double GTIFAngleToDD( double dfAngle, int nUOMAngle );
      45                 : CPL_C_END
      46                 : 
      47                 : // Key Macros from Makefile:
      48                 : //   MRSID_ESDK: Means we have the encoding SDK (version 5 or newer required)
      49                 : //   MRSID_J2K: Means we are enabling MrSID SDK JPEG2000 support. 
      50                 : 
      51                 : #include "lt_types.h"
      52                 : #include "lt_base.h"
      53                 : #include "lt_fileSpec.h"
      54                 : #include "lt_ioFileStream.h"
      55                 : #include "lt_utilStatusStrings.h"
      56                 : #include "lti_geoCoord.h"
      57                 : #include "lti_pixel.h"
      58                 : #include "lti_navigator.h"
      59                 : #include "lti_sceneBuffer.h"
      60                 : #include "lti_metadataDatabase.h"
      61                 : #include "lti_metadataRecord.h"
      62                 : #include "lti_utils.h"
      63                 : #include "lti_delegates.h"
      64                 : #include "lt_utilStatus.h"
      65                 : #include "MrSIDImageReader.h"
      66                 : 
      67                 : #ifdef MRSID_J2K
      68                 : #  include "J2KImageReader.h"
      69                 : #endif
      70                 : 
      71                 : // It seems that LT_STS_UTIL_TimeUnknown was added in version 6, also
      72                 : // the first version with lti_version.h
      73                 : #ifdef LT_STS_UTIL_TimeUnknown
      74                 : #  include "lti_version.h"
      75                 : #endif
      76                 : 
      77                 : // Are we using version 6 or newer?
      78                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
      79                 : #  define MRSID_POST5
      80                 : #endif
      81                 : 
      82                 : #ifdef MRSID_ESDK
      83                 : # include "MG3ImageWriter.h"
      84                 : # include "MG3WriterParams.h"
      85                 : # include "MG2ImageWriter.h"
      86                 : # include "MG2WriterParams.h"
      87                 : # ifdef MRSID_HAVE_MG4WRITE
      88                 : #   include "MG4ImageWriter.h"
      89                 : #   include "MG4WriterParams.h"
      90                 : # endif
      91                 : # ifdef MRSID_J2K
      92                 : #   ifdef MRSID_POST5
      93                 : #     include "JP2WriterManager.h"
      94                 : #     include "JPCWriterParams.h"
      95                 : #   else
      96                 : #     include "J2KImageWriter.h"
      97                 : #     include "J2KWriterParams.h"
      98                 : #   endif
      99                 : # endif
     100                 : #endif /* MRSID_ESDK */
     101                 : 
     102                 : #ifdef MRSID_POST5
     103                 : #  define MRSID_HAVE_GETWKT
     104                 : #endif
     105                 : 
     106                 : #include "mrsidstream.h"
     107                 : 
     108                 : LT_USE_NAMESPACE(LizardTech)
     109                 : 
     110                 : /* -------------------------------------------------------------------- */
     111                 : /*      Various wrapper templates used to force new/delete to happen    */
     112                 : /*      in the same heap.  See bug 1213 and MSDN knowledgebase          */
     113                 : /*      article 122675.                                                 */
     114                 : /* -------------------------------------------------------------------- */
     115                 : 
     116                 : template <class T>
     117                 : class LTIDLLPixel : public T
     118                 : {
     119                 : public:
     120             226 :    LTIDLLPixel(LTIColorSpace colorSpace,
     121                 :             lt_uint16 numBands,
     122             226 :             LTIDataType dataType) : T(colorSpace,numBands,dataType) {}
     123             226 :    virtual ~LTIDLLPixel() {};
     124                 : };
     125                 : 
     126                 : template <class T>
     127                 : class LTIDLLReader : public T
     128                 : {
     129                 : public:
     130                 :    LTIDLLReader(const LTFileSpec& fileSpec,
     131                 :                 bool useWorldFile = false) : T(fileSpec, useWorldFile) {}
     132                 :    LTIDLLReader(LTIOStreamInf &oStream,
     133                 :                 bool useWorldFile = false) : T(oStream, useWorldFile) {}
     134                 :    LTIDLLReader(LTIOStreamInf *poStream,
     135                 :                 LTIOStreamInf *poWorldFile = NULL) : T(poStream, poWorldFile) {}
     136                 :    virtual ~LTIDLLReader() {};
     137                 : };
     138                 : 
     139                 : template <class T>
     140                 : class LTIDLLNavigator : public T
     141                 : {
     142                 : public:
     143             142 :    LTIDLLNavigator(const LTIImage& image ) : T(image) {}
     144             142 :    virtual ~LTIDLLNavigator() {};
     145                 : };
     146                 : 
     147                 : template <class T>
     148                 : class LTIDLLBuffer : public T
     149                 : {
     150                 : public:
     151              18 :    LTIDLLBuffer(const LTIPixel& pixelProps,
     152                 :                   lt_uint32 totalNumCols,
     153                 :                   lt_uint32 totalNumRows,
     154              18 :                   void** data ) : T(pixelProps,totalNumCols,totalNumRows,data) {}
     155              18 :    virtual ~LTIDLLBuffer() {};
     156                 : };
     157                 : 
     158                 : template <class T>
     159                 : class LTIDLLCopy : public T
     160                 : {
     161                 : public:
     162              27 :    LTIDLLCopy(const T& original) : T(original) {}
     163              27 :    virtual ~LTIDLLCopy() {};
     164                 : };
     165                 : 
     166                 : template <class T>
     167                 : class LTIDLLWriter : public T
     168                 : {
     169                 : public:
     170                 :     LTIDLLWriter(LTIImageStage *image) : T(image) {}
     171                 :     virtual ~LTIDLLWriter() {}
     172                 : };
     173                 : 
     174                 : template <class T>
     175                 : class LTIDLLDefault : public T
     176                 : {
     177                 : public:
     178                 :     LTIDLLDefault() : T() {}
     179                 :     virtual ~LTIDLLDefault() {}
     180                 : };
     181                 : 
     182                 : /* -------------------------------------------------------------------- */
     183                 : /*      Interface to MrSID SDK progress reporting.                      */
     184                 : /* -------------------------------------------------------------------- */
     185                 : 
     186                 : class MrSIDProgress : public LTIProgressDelegate
     187                 : {
     188                 : public:
     189                 :     MrSIDProgress(GDALProgressFunc f, void *arg) : m_f(f), m_arg(arg) {}
     190                 :     virtual ~MrSIDProgress() {}
     191                 :     virtual LT_STATUS setProgressStatus(float fraction)
     192                 :     {
     193                 :         if (!m_f)
     194                 :             return LT_STS_BadContext;
     195                 :         if( !m_f( fraction, NULL, m_arg ) )
     196                 :             return LT_STS_Failure;
     197                 :         return LT_STS_Success;
     198                 :     }
     199                 : private:
     200                 :     GDALProgressFunc m_f;
     201                 :     void *m_arg;
     202                 : };
     203                 : 
     204                 : /************************************************************************/
     205                 : /* ==================================================================== */
     206                 : /*                              MrSIDDataset                            */
     207                 : /* ==================================================================== */
     208                 : /************************************************************************/
     209                 : 
     210                 : class MrSIDDataset : public GDALPamDataset
     211                 : {
     212                 :     friend class MrSIDRasterBand;
     213                 : 
     214                 :     LTIOStreamInf       *poStream;
     215                 :     LTIOFileStream      oLTIStream;
     216                 :     LTIVSIStream        oVSIStream;
     217                 : 
     218                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
     219                 :     LTIImageFilter      *poImageReader;
     220                 : #else
     221                 :     LTIImageReader      *poImageReader;
     222                 : #endif
     223                 : 
     224                 : #ifdef MRSID_ESDK
     225                 :     LTIGeoFileImageWriter *poImageWriter;
     226                 : #endif
     227                 : 
     228                 :     LTIDLLNavigator<LTINavigator>  *poLTINav;
     229                 :     LTIDLLCopy<LTIMetadataDatabase> *poMetadata;
     230                 :     const LTIPixel      *poNDPixel;
     231                 : 
     232                 :     LTIDLLBuffer<LTISceneBuffer>  *poBuffer;
     233                 :     int                 nBlockXSize, nBlockYSize;
     234                 :     int                 bPrevBlockRead;
     235                 :     int                 nPrevBlockXOff, nPrevBlockYOff;
     236                 : 
     237                 :     LTIDataType         eSampleType;
     238                 :     GDALDataType        eDataType;
     239                 :     LTIColorSpace       eColorSpace;
     240                 : 
     241                 :     double              dfCurrentMag;
     242                 : 
     243                 :     int                 bHasGeoTransform;
     244                 :     double              adfGeoTransform[6];
     245                 :     char                *pszProjection;
     246                 :     GTIFDefn            *psDefn;
     247                 : 
     248                 :     MrSIDDataset       *poParentDS;
     249                 :     int                 bIsOverview;
     250                 :     int                 nOverviewCount;
     251                 :     MrSIDDataset        **papoOverviewDS;
     252                 : 
     253                 :     CPLString           osMETFilename;
     254                 : 
     255                 :     CPLErr              OpenZoomLevel( lt_int32 iZoom );
     256                 :     char                *SerializeMetadataRec( const LTIMetadataRecord* );
     257                 :     int                 GetMetadataElement( const char *, void *, int=0 );
     258                 :     void                FetchProjParms();
     259                 :     void                GetGTIFDefn();
     260                 :     char                *GetOGISDefn( GTIFDefn * );
     261                 : 
     262                 :     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int, void *,
     263                 :                                    int, int, GDALDataType, int, int *,int,
     264                 :                                    int, int );
     265                 : 
     266                 :   protected:
     267                 :     virtual int         CloseDependentDatasets();
     268                 : 
     269                 :     virtual CPLErr      IBuildOverviews( const char *, int, int *,
     270                 :                                          int, int *, GDALProgressFunc, void * );
     271                 : 
     272                 :   public:
     273                 :                 MrSIDDataset(int bIsJPEG2000);
     274                 :                 ~MrSIDDataset();
     275                 : 
     276                 :     static GDALDataset  *Open( GDALOpenInfo * poOpenInfo, int bIsJP2 );
     277                 :     virtual CPLErr      GetGeoTransform( double * padfTransform );
     278                 :     const char          *GetProjectionRef();
     279                 : 
     280                 :     virtual char      **GetFileList();
     281                 : 
     282                 : #ifdef MRSID_ESDK
     283                 :     static GDALDataset  *Create( const char * pszFilename,
     284                 :                                  int nXSize, int nYSize, int nBands,
     285                 :                                  GDALDataType eType, char ** papszParmList );
     286                 :     virtual void        FlushCache( void );
     287                 : #endif
     288                 : };
     289                 : 
     290                 : /************************************************************************/
     291                 : /* ==================================================================== */
     292                 : /*                           MrSIDRasterBand                            */
     293                 : /* ==================================================================== */
     294                 : /************************************************************************/
     295                 : 
     296                 : class MrSIDRasterBand : public GDALPamRasterBand
     297                 : {
     298                 :     friend class MrSIDDataset;
     299                 : 
     300                 :     LTIPixel        *poPixel;
     301                 : 
     302                 :     int             nBlockSize;
     303                 : 
     304                 :     int             bNoDataSet;
     305                 :     double          dfNoDataValue;
     306                 : 
     307                 :     MrSIDDataset    *poGDS;
     308                 : 
     309                 :     GDALColorInterp eBandInterp;
     310                 : 
     311                 :   public:
     312                 : 
     313                 :                 MrSIDRasterBand( MrSIDDataset *, int );
     314                 :                 ~MrSIDRasterBand();
     315                 : 
     316                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
     317                 :                               void *, int, int, GDALDataType,
     318                 :                               int, int );
     319                 : 
     320                 :     virtual CPLErr          IReadBlock( int, int, void * );
     321                 :     virtual GDALColorInterp GetColorInterpretation();
     322                 :     CPLErr                  SetColorInterpretation( GDALColorInterp eNewInterp );
     323                 :     virtual double          GetNoDataValue( int * );
     324                 :     virtual int             GetOverviewCount();
     325                 :     virtual GDALRasterBand  *GetOverview( int );
     326                 : 
     327                 :     virtual CPLErr GetStatistics( int bApproxOK, int bForce,
     328                 :                                   double *pdfMin, double *pdfMax, 
     329                 :                                   double *pdfMean, double *pdfStdDev );
     330                 : 
     331                 : #ifdef MRSID_ESDK
     332                 :     virtual CPLErr          IWriteBlock( int, int, void * );
     333                 : #endif
     334                 : };
     335                 : 
     336                 : /************************************************************************/
     337                 : /*                           MrSIDRasterBand()                          */
     338                 : /************************************************************************/
     339                 : 
     340             226 : MrSIDRasterBand::MrSIDRasterBand( MrSIDDataset *poDS, int nBand )
     341                 : {
     342             226 :     this->poDS = poDS;
     343             226 :     poGDS = poDS;
     344             226 :     this->nBand = nBand;
     345             226 :     this->eDataType = poDS->eDataType;
     346                 : 
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Set the block sizes and buffer parameters.                      */
     349                 : /* -------------------------------------------------------------------- */
     350             226 :     nBlockXSize = poDS->nBlockXSize;
     351             226 :     nBlockYSize = poDS->nBlockYSize;
     352                 : //#ifdef notdef
     353             226 :     if( poDS->GetRasterXSize() > 2048 )
     354               6 :         nBlockXSize = 1024;
     355             226 :     if( poDS->GetRasterYSize() > 128 )
     356              87 :         nBlockYSize = 128;
     357                 :     else
     358             139 :         nBlockYSize = poDS->GetRasterYSize();
     359                 : //#endif
     360                 : 
     361             226 :     nBlockSize = nBlockXSize * nBlockYSize;
     362                 :     poPixel = new LTIDLLPixel<LTIPixel>( poDS->eColorSpace, poDS->nBands,
     363             226 :                                          poDS->eSampleType );
     364                 : 
     365                 : 
     366                 : /* -------------------------------------------------------------------- */
     367                 : /*      Set NoData values.                                              */
     368                 : /*                                                                      */
     369                 : /*      This logic is disabled for now since the MrSID nodata           */
     370                 : /*      semantics are different than GDAL.  In MrSID all bands must     */
     371                 : /*      match the nodata value for that band in order for the pixel     */
     372                 : /*      to be considered nodata, otherwise all values are valid.        */
     373                 : /* -------------------------------------------------------------------- */
     374                 : #ifdef notdef
     375                 :      if ( poDS->poNDPixel )
     376                 :      {
     377                 :          switch( poDS->eSampleType )
     378                 :          {
     379                 :              case LTI_DATATYPE_UINT8:
     380                 :              case LTI_DATATYPE_SINT8:
     381                 :                  dfNoDataValue = (double)
     382                 :                      poDS->poNDPixel->getSampleValueUint8( nBand - 1 );
     383                 :                  break;
     384                 :              case LTI_DATATYPE_UINT16:
     385                 :                  dfNoDataValue = (double)
     386                 :                      poDS->poNDPixel->getSampleValueUint16( nBand - 1 );
     387                 :                  break;
     388                 :              case LTI_DATATYPE_FLOAT32:
     389                 :                  dfNoDataValue =
     390                 :                      poDS->poNDPixel->getSampleValueFloat32( nBand - 1 );
     391                 :                  break;
     392                 :              case LTI_DATATYPE_SINT16:
     393                 :                  dfNoDataValue = (double)
     394                 :                      *(GInt16 *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
     395                 :                  break;
     396                 :              case LTI_DATATYPE_UINT32:
     397                 :                  dfNoDataValue = (double)
     398                 :                      *(GUInt32 *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
     399                 :                  break;
     400                 :              case LTI_DATATYPE_SINT32:
     401                 :                  dfNoDataValue = (double)
     402                 :                      *(GInt32 *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
     403                 :                  break;
     404                 :              case LTI_DATATYPE_FLOAT64:
     405                 :                  dfNoDataValue =
     406                 :                      *(double *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
     407                 :                  break;
     408                 : 
     409                 :              case LTI_DATATYPE_INVALID:
     410                 :                  CPLAssert( FALSE );
     411                 :                  break;
     412                 :          }
     413                 :          bNoDataSet = TRUE;
     414                 :      }
     415                 :      else
     416                 : #endif
     417                 :      {
     418             226 :         dfNoDataValue = 0.0;
     419             226 :         bNoDataSet = FALSE;
     420                 :      }
     421                 : 
     422             226 :     switch( poGDS->eColorSpace )
     423                 :     {
     424                 :         case LTI_COLORSPACE_RGB:
     425             126 :             if( nBand == 1 )
     426              42 :                 eBandInterp = GCI_RedBand;
     427              84 :             else if( nBand == 2 )
     428              42 :                 eBandInterp = GCI_GreenBand;
     429              42 :             else if( nBand == 3 )
     430              42 :                 eBandInterp = GCI_BlueBand;
     431                 :             else
     432               0 :                 eBandInterp = GCI_Undefined;
     433             126 :             break;
     434                 : 
     435                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
     436                 :         case LTI_COLORSPACE_RGBA:
     437               0 :             if( nBand == 1 )
     438               0 :                 eBandInterp = GCI_RedBand;
     439               0 :             else if( nBand == 2 )
     440               0 :                 eBandInterp = GCI_GreenBand;
     441               0 :             else if( nBand == 3 )
     442               0 :                 eBandInterp = GCI_BlueBand;
     443               0 :             else if( nBand == 4 )
     444               0 :                 eBandInterp = GCI_AlphaBand;
     445                 :             else
     446               0 :                 eBandInterp = GCI_Undefined;
     447               0 :             break;
     448                 : #endif
     449                 : 
     450                 :         case LTI_COLORSPACE_CMYK:
     451               0 :             if( nBand == 1 )
     452               0 :                 eBandInterp = GCI_CyanBand;
     453               0 :             else if( nBand == 2 )
     454               0 :                 eBandInterp = GCI_MagentaBand;
     455               0 :             else if( nBand == 3 )
     456               0 :                 eBandInterp = GCI_YellowBand;
     457               0 :             else if( nBand == 4 )
     458               0 :                 eBandInterp = GCI_BlackBand;
     459                 :             else
     460               0 :                 eBandInterp = GCI_Undefined;
     461               0 :             break;
     462                 : 
     463                 :         case LTI_COLORSPACE_GRAYSCALE:
     464              94 :             eBandInterp = GCI_GrayIndex;
     465              94 :             break;
     466                 : 
     467                 :         default:
     468               6 :             eBandInterp = GCI_Undefined;
     469                 :             break;
     470                 :     }
     471             226 : }
     472                 : 
     473                 : /************************************************************************/
     474                 : /*                            ~MrSIDRasterBand()                        */
     475                 : /************************************************************************/
     476                 : 
     477             226 : MrSIDRasterBand::~MrSIDRasterBand()
     478                 : {
     479             226 :     if ( poPixel )
     480             226 :         delete poPixel;
     481             226 : }
     482                 : 
     483                 : /************************************************************************/
     484                 : /*                             IReadBlock()                             */
     485                 : /************************************************************************/
     486                 : 
     487              99 : CPLErr MrSIDRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     488                 :                                     void * pImage )
     489                 : {
     490                 : #ifdef MRSID_ESDK
     491                 :     if( poGDS->eAccess == GA_Update )
     492                 :     {
     493                 :         CPLDebug( "MrSID", 
     494                 :                   "IReadBlock() - DSDK - read on updatable file fails." );
     495                 :         memset( pImage, 0, nBlockSize * GDALGetDataTypeSize(eDataType) / 8 );
     496                 :         return CE_None;
     497                 :     }
     498                 : #endif /* MRSID_ESDK */
     499                 : 
     500              99 :     CPLDebug( "MrSID", "IReadBlock(%d,%d)", nBlockXOff, nBlockYOff );
     501                 : 
     502              99 :     if ( !poGDS->bPrevBlockRead
     503                 :          || poGDS->nPrevBlockXOff != nBlockXOff
     504                 :          || poGDS->nPrevBlockYOff != nBlockYOff )
     505                 :     {
     506              97 :         GInt32      nLine = nBlockYOff * nBlockYSize;
     507              97 :         GInt32      nCol = nBlockXOff * nBlockXSize;
     508                 : 
     509                 :         // XXX: The scene, passed to LTIImageStage::read() call must be
     510                 :         // inside the image boundaries. So we should detect the last strip and
     511                 :         // form the scene properly.
     512                 :         CPLDebug( "MrSID", 
     513                 :                   "IReadBlock - read() %dx%d block at %d,%d.", 
     514              97 :                   nBlockXSize, nBlockYSize, nCol, nLine );
     515                 :                   
     516              97 :         if(!LT_SUCCESS( poGDS->poLTINav->setSceneAsULWH(
     517                 :                             nCol, nLine,
     518                 :                             (nCol+nBlockXSize>poGDS->GetRasterXSize())?
     519                 :                             (poGDS->GetRasterXSize()-nCol):nBlockXSize,
     520                 :                             (nLine+nBlockYSize>poGDS->GetRasterYSize())?
     521                 :                             (poGDS->GetRasterYSize()-nLine):nBlockYSize,
     522                 :                             poGDS->dfCurrentMag) ))
     523                 :             
     524                 :         {
     525                 :             CPLError( CE_Failure, CPLE_AppDefined,
     526               0 :                       "MrSIDRasterBand::IReadBlock(): Failed to set scene position." );
     527               0 :             return CE_Failure;
     528                 :         }
     529                 : 
     530              97 :         if ( !poGDS->poBuffer )
     531                 :         {
     532                 :             poGDS->poBuffer =
     533              18 :                 new LTIDLLBuffer<LTISceneBuffer>( *poPixel, nBlockXSize, nBlockYSize, NULL );
     534                 : //            poGDS->poBuffer =
     535                 : //                new LTISceneBuffer( *poPixel, nBlockXSize, nBlockYSize, NULL );
     536                 :         }
     537                 : 
     538              97 :         if(!LT_SUCCESS(poGDS->poImageReader->read(poGDS->poLTINav->getScene(),
     539                 :                                                   *poGDS->poBuffer)))
     540                 :         {
     541                 :             CPLError( CE_Failure, CPLE_AppDefined,
     542               0 :                       "MrSIDRasterBand::IReadBlock(): Failed to load image." );
     543               0 :             return CE_Failure;
     544                 :         }
     545                 : 
     546              97 :         poGDS->bPrevBlockRead = TRUE;
     547              97 :         poGDS->nPrevBlockXOff = nBlockXOff;
     548              97 :         poGDS->nPrevBlockYOff = nBlockYOff;
     549                 :     }
     550                 : 
     551                 :     memcpy( pImage, poGDS->poBuffer->getTotalBandData(nBand - 1), 
     552              99 :             nBlockSize * (GDALGetDataTypeSize(poGDS->eDataType) / 8) );
     553                 : 
     554              99 :     return CE_None;
     555                 : }
     556                 : 
     557                 : #ifdef MRSID_ESDK
     558                 : 
     559                 : /************************************************************************/
     560                 : /*                            IWriteBlock()                             */
     561                 : /************************************************************************/
     562                 : 
     563                 : CPLErr MrSIDRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     564                 :                                      void * pImage )
     565                 : {
     566                 :     CPLAssert( poGDS != NULL
     567                 :                && nBlockXOff >= 0
     568                 :                && nBlockYOff >= 0
     569                 :                && pImage != NULL );
     570                 : 
     571                 : #if DEBUG
     572                 :     CPLDebug( "MrSID", "IWriteBlock(): nBlockXOff=%d, nBlockYOff=%d",
     573                 :               nBlockXOff, nBlockYOff );
     574                 : #endif
     575                 : 
     576                 :     LTIScene        oScene( nBlockXOff * nBlockXSize,
     577                 :                             nBlockYOff * nBlockYSize,
     578                 :                             nBlockXSize, nBlockYSize, 1.0);
     579                 :     LTISceneBuffer  oSceneBuf( *poPixel, poGDS->nBlockXSize,
     580                 :                                poGDS->nBlockYSize, &pImage );
     581                 : 
     582                 :     if( !LT_SUCCESS(poGDS->poImageWriter->writeBegin(oScene)) )
     583                 :     {
     584                 :         CPLError( CE_Failure, CPLE_AppDefined,
     585                 :                   "MrSIDRasterBand::IWriteBlock(): writeBegin failed." );
     586                 :         return CE_Failure;
     587                 :     }
     588                 : 
     589                 :     if( !LT_SUCCESS(poGDS->poImageWriter->writeStrip(oSceneBuf, oScene)) )
     590                 :     {
     591                 :         CPLError( CE_Failure, CPLE_AppDefined,
     592                 :                   "MrSIDRasterBand::IWriteBlock(): writeStrip failed." );
     593                 :         return CE_Failure;
     594                 :     }
     595                 : 
     596                 :     if( !LT_SUCCESS(poGDS->poImageWriter->writeEnd()) )
     597                 :     {
     598                 :         CPLError( CE_Failure, CPLE_AppDefined,
     599                 :                   "MrSIDRasterBand::IWriteBlock(): writeEnd failed." );
     600                 :         return CE_Failure;
     601                 :     }
     602                 : 
     603                 :     return CE_None;
     604                 : }
     605                 : 
     606                 : #endif /* MRSID_ESDK */
     607                 : 
     608                 : /************************************************************************/
     609                 : /*                             IRasterIO()                              */
     610                 : /************************************************************************/
     611                 : 
     612            6893 : CPLErr MrSIDRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     613                 :                                    int nXOff, int nYOff, int nXSize, int nYSize,
     614                 :                                    void * pData, int nBufXSize, int nBufYSize,
     615                 :                                    GDALDataType eBufType,
     616                 :                                    int nPixelSpace, int nLineSpace )
     617                 :     
     618                 : {
     619                 : /* -------------------------------------------------------------------- */
     620                 : /*      Fallback to default implementation if the whole scanline        */
     621                 : /*      without subsampling requested.                                  */
     622                 : /* -------------------------------------------------------------------- */
     623            6893 :     if ( nXSize == poGDS->GetRasterXSize()
     624                 :          && nXSize == nBufXSize
     625                 :          && nYSize == nBufYSize )
     626                 :     {
     627                 :         return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff,
     628                 :                                           nXSize, nYSize, pData,
     629                 :                                           nBufXSize, nBufYSize, eBufType,
     630            6892 :                                           nPixelSpace, nLineSpace );
     631                 :     }
     632                 : 
     633                 : /* -------------------------------------------------------------------- */
     634                 : /*      Handle via the dataset level IRasterIO()                        */
     635                 : /* -------------------------------------------------------------------- */
     636                 :     return poGDS->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, 
     637                 :                              nBufXSize, nBufYSize, eBufType, 
     638               1 :                              1, &nBand, nPixelSpace, nLineSpace, 0 );
     639                 : }
     640                 : 
     641                 : /************************************************************************/
     642                 : /*                       GetColorInterpretation()                       */
     643                 : /************************************************************************/
     644                 : 
     645               6 : GDALColorInterp MrSIDRasterBand::GetColorInterpretation()
     646                 : 
     647                 : {
     648               6 :     return eBandInterp;
     649                 : }
     650                 : 
     651                 : /************************************************************************/
     652                 : /*                       SetColorInterpretation()                       */
     653                 : /*                                                                      */
     654                 : /*      This would normally just be used by folks using the MrSID code  */
     655                 : /*      to read JP2 streams in other formats (such as NITF) and         */
     656                 : /*      providing their own color interpretation regardless of what     */
     657                 : /*      MrSID might think the stream itself says.                       */
     658                 : /************************************************************************/
     659                 : 
     660               0 : CPLErr MrSIDRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
     661                 : 
     662                 : {
     663               0 :     eBandInterp = eNewInterp;
     664                 : 
     665               0 :     return CE_None;
     666                 : }
     667                 : 
     668                 : /************************************************************************/
     669                 : /*                           GetStatistics()                            */
     670                 : /*                                                                      */
     671                 : /*      We override this method so that we can force generation of      */
     672                 : /*      statistics if approx ok is true since we know that a small      */
     673                 : /*      overview is always available, and that computing statistics     */
     674                 : /*      from it is very fast.                                           */
     675                 : /************************************************************************/
     676                 : 
     677               7 : CPLErr MrSIDRasterBand::GetStatistics( int bApproxOK, int bForce,
     678                 :                                        double *pdfMin, double *pdfMax, 
     679                 :                                        double *pdfMean, double *pdfStdDev )
     680                 : 
     681                 : {
     682               7 :     if( bApproxOK )
     683               4 :         bForce = TRUE;
     684                 : 
     685                 :     return GDALPamRasterBand::GetStatistics( bApproxOK, bForce, 
     686                 :                                              pdfMin, pdfMax, 
     687               7 :                                              pdfMean, pdfStdDev );
     688                 : }
     689                 : 
     690                 : /************************************************************************/
     691                 : /*                           GetNoDataValue()                           */
     692                 : /************************************************************************/
     693                 : 
     694               8 : double MrSIDRasterBand::GetNoDataValue( int * pbSuccess )
     695                 : 
     696                 : {
     697               8 :     if( bNoDataSet )
     698                 :     {
     699               0 :         if( pbSuccess )
     700               0 :             *pbSuccess = bNoDataSet;
     701                 : 
     702               0 :         return dfNoDataValue;
     703                 :     }
     704                 : 
     705               8 :     return GDALPamRasterBand::GetNoDataValue( pbSuccess );
     706                 : }
     707                 : 
     708                 : /************************************************************************/
     709                 : /*                          GetOverviewCount()                          */
     710                 : /************************************************************************/
     711                 : 
     712              27 : int MrSIDRasterBand::GetOverviewCount()
     713                 : 
     714                 : {
     715              27 :     return poGDS->nOverviewCount;
     716                 : }
     717                 : 
     718                 : /************************************************************************/
     719                 : /*                            GetOverview()                             */
     720                 : /************************************************************************/
     721                 : 
     722              19 : GDALRasterBand *MrSIDRasterBand::GetOverview( int i )
     723                 : 
     724                 : {
     725              19 :     if( i < 0 || i >= poGDS->nOverviewCount )
     726               0 :         return NULL;
     727                 :     else
     728              19 :         return poGDS->papoOverviewDS[i]->GetRasterBand( nBand );
     729                 : }
     730                 : 
     731                 : /************************************************************************/
     732                 : /*                           MrSIDDataset()                             */
     733                 : /************************************************************************/
     734                 : 
     735             142 : MrSIDDataset::MrSIDDataset(int bIsJPEG2000)
     736                 : {
     737             142 :     poStream = NULL;
     738             142 :     poImageReader = NULL;
     739                 : #ifdef MRSID_ESDK
     740                 :     poImageWriter = NULL;
     741                 : #endif
     742             142 :     poLTINav = NULL;
     743             142 :     poMetadata = NULL;
     744             142 :     poNDPixel = NULL;
     745             142 :     eSampleType = LTI_DATATYPE_UINT8;
     746             142 :     nBands = 0;
     747             142 :     eDataType = GDT_Byte;
     748                 :     
     749             142 :     poBuffer = NULL;
     750             142 :     bPrevBlockRead = FALSE;
     751             142 :     nPrevBlockXOff = 0;
     752             142 :     nPrevBlockYOff = 0;
     753                 :     
     754             142 :     pszProjection = CPLStrdup( "" );
     755             142 :     bHasGeoTransform = FALSE;
     756             142 :     adfGeoTransform[0] = 0.0;
     757             142 :     adfGeoTransform[1] = 1.0;
     758             142 :     adfGeoTransform[2] = 0.0;
     759             142 :     adfGeoTransform[3] = 0.0;
     760             142 :     adfGeoTransform[4] = 0.0;
     761             142 :     adfGeoTransform[5] = 1.0;
     762             142 :     psDefn = NULL;
     763                 :     
     764             142 :     dfCurrentMag = 1.0;
     765             142 :     bIsOverview = FALSE;
     766             142 :     poParentDS = this;
     767             142 :     nOverviewCount = 0;
     768             142 :     papoOverviewDS = NULL;
     769                 :     
     770             142 :     poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2MrSID" : "MrSID" );
     771             142 : }
     772                 : 
     773                 : /************************************************************************/
     774                 : /*                            ~MrSIDDataset()                           */
     775                 : /************************************************************************/
     776                 : 
     777             142 : MrSIDDataset::~MrSIDDataset()
     778                 : {
     779             142 :     FlushCache();
     780                 : 
     781                 : #ifdef MRSID_ESDK
     782                 :     if ( poImageWriter )
     783                 :         delete poImageWriter;
     784                 : #endif
     785                 : 
     786             142 :     if ( poBuffer )
     787              18 :         delete poBuffer;
     788             142 :     if ( poMetadata )
     789              27 :         delete poMetadata;
     790             142 :     if ( poLTINav )
     791             142 :         delete poLTINav;
     792             142 :     if ( poImageReader && !bIsOverview )
     793                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
     794                 :     {
     795              27 :         poImageReader->release();
     796              27 :         poImageReader = NULL;
     797                 :     }
     798                 : #else
     799                 :         delete poImageReader;
     800                 : #endif
     801                 :     // points to another member, don't delete
     802             142 :     poStream = NULL;
     803                 : 
     804             142 :     if ( pszProjection )
     805             142 :         CPLFree( pszProjection );
     806             142 :     if ( psDefn )
     807              27 :         delete psDefn;
     808             142 :     CloseDependentDatasets();
     809             142 : }
     810                 : 
     811                 : /************************************************************************/
     812                 : /*                      CloseDependentDatasets()                        */
     813                 : /************************************************************************/
     814                 : 
     815             142 : int MrSIDDataset::CloseDependentDatasets()
     816                 : {
     817             142 :     int bRet = GDALPamDataset::CloseDependentDatasets();
     818                 : 
     819             142 :     if ( papoOverviewDS )
     820                 :     {
     821             140 :         for( int i = 0; i < nOverviewCount; i++ )
     822             115 :             delete papoOverviewDS[i];
     823              25 :         CPLFree( papoOverviewDS );
     824              25 :         papoOverviewDS = NULL;
     825              25 :         bRet = TRUE;
     826                 :     }
     827             142 :     return bRet;
     828                 : }
     829                 : 
     830                 : /************************************************************************/
     831                 : /*                             IRasterIO()                              */
     832                 : /************************************************************************/
     833                 : 
     834               2 : CPLErr MrSIDDataset::IRasterIO( GDALRWFlag eRWFlag,
     835                 :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     836                 :                                 void * pData, int nBufXSize, int nBufYSize,
     837                 :                                 GDALDataType eBufType, 
     838                 :                                 int nBandCount, int *panBandMap,
     839                 :                                 int nPixelSpace, int nLineSpace, int nBandSpace )
     840                 : 
     841                 : {
     842                 : /* -------------------------------------------------------------------- */
     843                 : /*      We need various criteria to skip out to block based methods.    */
     844                 : /* -------------------------------------------------------------------- */
     845               2 :     int bUseBlockedIO = bForceCachedIO;
     846                 : 
     847               2 :     if( nYSize == 1 || nXSize * ((double) nYSize) < 100.0 )
     848               0 :         bUseBlockedIO = TRUE;
     849                 : 
     850               2 :     if( nBufYSize == 1 || nBufXSize * ((double) nBufYSize) < 100.0 )
     851               0 :         bUseBlockedIO = TRUE;
     852                 : 
     853               2 :     if( CSLTestBoolean( CPLGetConfigOption( "GDAL_ONE_BIG_READ", "NO") ) )
     854               0 :         bUseBlockedIO = FALSE;
     855                 : 
     856               2 :     if( bUseBlockedIO )
     857                 :         return GDALDataset::BlockBasedRasterIO( 
     858                 :             eRWFlag, nXOff, nYOff, nXSize, nYSize,
     859                 :             pData, nBufXSize, nBufYSize, eBufType, 
     860               0 :             nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
     861               2 :     CPLDebug( "MrSID", "RasterIO() - using optimized dataset level IO." );
     862                 :     
     863                 : /* -------------------------------------------------------------------- */
     864                 : /*      What is our requested window relative to the base dataset.      */
     865                 : /*      We want to operate from here on as if we were operating on      */
     866                 : /*      the full res band.                                              */
     867                 : /* -------------------------------------------------------------------- */
     868               2 :     int nZoomMag = (int) ((1/dfCurrentMag) * 1.0000001);
     869                 : 
     870               2 :     nXOff *= nZoomMag;
     871               2 :     nYOff *= nZoomMag;
     872               2 :     nXSize *= nZoomMag;
     873               2 :     nYSize *= nZoomMag;
     874                 : 
     875                 : /* -------------------------------------------------------------------- */
     876                 : /*      We need to figure out the best zoom level to use for this       */
     877                 : /*      request.  We apply a small fudge factor to make sure that       */
     878                 : /*      request just very, very slightly larger than a zoom level do    */
     879                 : /*      not force us to the next level.                                 */
     880                 : /* -------------------------------------------------------------------- */
     881               2 :     int iOverview = 0;
     882               2 :     double dfZoomMag = MIN((nXSize / (double)nBufXSize), 
     883                 :                            (nYSize / (double)nBufYSize));
     884                 : 
     885               2 :     for( nZoomMag = 1; 
     886                 :          nZoomMag * 2 < (dfZoomMag + 0.1) 
     887                 :              && iOverview < poParentDS->nOverviewCount; 
     888                 :          nZoomMag *= 2, iOverview++ ) {}
     889                 : 
     890                 : /* -------------------------------------------------------------------- */
     891                 : /*      Work out the size of the temporary buffer and allocate it.      */
     892                 : /*      The temporary buffer will generally be at a moderately          */
     893                 : /*      higher resolution than the buffer of data requested.            */
     894                 : /* -------------------------------------------------------------------- */
     895                 :     int  nTmpPixelSize;
     896               2 :     LTIPixel       oPixel( eColorSpace, nBands, eSampleType );
     897                 :     
     898                 :     LT_STATUS eLTStatus;
     899                 :     unsigned int maxWidth;
     900                 :     unsigned int maxHeight;
     901                 : 
     902               2 :     eLTStatus = poImageReader->getDimsAtMag(1.0/nZoomMag,maxWidth,maxHeight);
     903                 : 
     904               2 :     if( !LT_SUCCESS(eLTStatus)) {
     905                 :         CPLError( CE_Failure, CPLE_AppDefined,
     906                 :                   "MrSIDDataset::IRasterIO(): Failed to get zoomed image dimensions.\n%s",
     907               0 :                   getLastStatusString( eLTStatus ) );
     908               0 :         return CE_Failure;
     909                 :     }
     910                 : 
     911               2 :     int maxWidthAtL0 = bIsOverview?poParentDS->GetRasterXSize():this->GetRasterXSize();
     912               2 :     int maxHeightAtL0 = bIsOverview?poParentDS->GetRasterYSize():this->GetRasterYSize();
     913                 : 
     914               2 :     int sceneUlXOff = nXOff / nZoomMag;
     915               2 :     int sceneUlYOff = nYOff / nZoomMag;
     916               2 :     int sceneWidth  = (int)(nXSize * (double) maxWidth / (double)maxWidthAtL0 + 0.99);
     917               2 :     int sceneHeight = (int)(nYSize * (double) maxHeight / (double)maxHeightAtL0 + 0.99);
     918                 : 
     919               2 :     if( (sceneUlXOff + sceneWidth) > (int) maxWidth )
     920               0 :         sceneWidth = maxWidth - sceneUlXOff;
     921                 : 
     922               2 :     if( (sceneUlYOff + sceneHeight) > (int) maxHeight )
     923               0 :         sceneHeight = maxHeight - sceneUlYOff;
     924                 : 
     925               2 :     LTISceneBuffer oLTIBuffer( oPixel, sceneWidth, sceneHeight, NULL );
     926                 : 
     927               2 :     nTmpPixelSize = GDALGetDataTypeSize( eDataType ) / 8;
     928                 : 
     929                 : /* -------------------------------------------------------------------- */
     930                 : /*      Create navigator, and move to the requested scene area.         */
     931                 : /* -------------------------------------------------------------------- */
     932               2 :     LTINavigator oNav( *poImageReader );
     933                 :     
     934               2 :     if( !LT_SUCCESS(oNav.setSceneAsULWH( sceneUlXOff, sceneUlYOff, 
     935                 :                                          sceneWidth, sceneHeight, 
     936                 :                                          1.0 / nZoomMag )) )
     937                 :     {
     938                 :         CPLError( CE_Failure, CPLE_AppDefined,
     939               0 :                   "MrSIDDataset::IRasterIO(): Failed to set scene position." );
     940                 : 
     941               0 :         return CE_Failure;
     942                 :     }
     943                 : 
     944                 :     CPLDebug( "MrSID", 
     945                 :               "Dataset:IRasterIO(%d,%d %dx%d -> %dx%d -> %dx%d, zoom=%d)",
     946                 :               nXOff, nYOff, nXSize, nYSize, 
     947                 :               sceneWidth, sceneHeight,
     948                 :               nBufXSize, nBufYSize, 
     949               2 :               nZoomMag );
     950                 : 
     951               2 :     if( !oNav.isSceneValid() )
     952               0 :         CPLDebug( "MrSID", "LTINavigator in invalid state." );
     953                 : 
     954                 : /* -------------------------------------------------------------------- */
     955                 : /*      Read into the buffer.                                           */
     956                 : /* -------------------------------------------------------------------- */
     957                 : 
     958               2 :     eLTStatus = poImageReader->read(oNav.getScene(),oLTIBuffer);
     959               2 :     if(!LT_SUCCESS(eLTStatus) )
     960                 :     {
     961                 :         CPLError( CE_Failure, CPLE_AppDefined,
     962                 :                   "MrSIDRasterBand::IRasterIO(): Failed to load image.\n%s",
     963               0 :                   getLastStatusString( eLTStatus ) );
     964               0 :         return CE_Failure;
     965                 :     }
     966                 : 
     967                 : /* -------------------------------------------------------------------- */
     968                 : /*      If we are pulling the data at a matching resolution, try to     */
     969                 : /*      do a more direct copy without subsampling.                      */
     970                 : /* -------------------------------------------------------------------- */
     971                 :     int         iBufLine, iBufPixel;
     972                 : 
     973               3 :     if( nBufXSize == sceneWidth && nBufYSize == sceneHeight )
     974                 :     {
     975               2 :         for( int iBand = 0; iBand < nBandCount; iBand++ )
     976                 :         {
     977                 :             GByte *pabySrcBand = (GByte *) 
     978               1 :                 oLTIBuffer.getTotalBandData( panBandMap[iBand] - 1 );
     979                 :     
     980             257 :             for( int iLine = 0; iLine < nBufYSize; iLine++ )
     981                 :       {
     982                 :                 GDALCopyWords( pabySrcBand + iLine*nTmpPixelSize*sceneWidth,
     983                 :                                eDataType, nTmpPixelSize, 
     984                 :                                ((GByte *)pData) + iLine*nLineSpace 
     985                 :                                + iBand * nBandSpace, 
     986                 :                                eBufType, nPixelSpace,
     987             256 :                                nBufXSize );
     988                 :       }
     989                 :   }
     990                 :     }
     991                 : 
     992                 : /* -------------------------------------------------------------------- */
     993                 : /*      Manually resample to our target buffer.                         */
     994                 : /* -------------------------------------------------------------------- */
     995                 :     else
     996                 :     {
     997              11 :         for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
     998                 :   {
     999              10 :             int iTmpLine = (int) floor(((iBufLine+0.5) / nBufYSize)*sceneHeight);
    1000                 : 
    1001             110 :             for( iBufPixel = 0; iBufPixel < nBufXSize; iBufPixel++ )
    1002                 :       {
    1003                 :                 int iTmpPixel = (int) 
    1004             100 :                     floor(((iBufPixel+0.5) / nBufXSize) * sceneWidth);
    1005                 : 
    1006             200 :                 for( int iBand = 0; iBand < nBandCount; iBand++ )
    1007                 :     {
    1008                 :                     GByte *pabySrc, *pabyDst;
    1009                 : 
    1010                 :                     pabyDst = ((GByte *) pData) 
    1011                 :                         + nPixelSpace * iBufPixel
    1012                 :                         + nLineSpace * iBufLine
    1013             100 :                         + nBandSpace * iBand;
    1014                 : 
    1015                 :                     pabySrc = (GByte *) oLTIBuffer.getTotalBandData( 
    1016             100 :                         panBandMap[iBand] - 1 );
    1017             100 :                     pabySrc += (iTmpLine * sceneWidth + iTmpPixel) * nTmpPixelSize;
    1018                 : 
    1019             100 :                     if( eDataType == eBufType )
    1020             100 :                         memcpy( pabyDst, pabySrc, nTmpPixelSize );
    1021                 :                     else
    1022                 :                         GDALCopyWords( pabySrc, eDataType, 0, 
    1023               0 :                                        pabyDst, eBufType, 0, 1 );
    1024                 :     }
    1025                 :       }
    1026                 :   }
    1027                 :     }
    1028                 : 
    1029               2 :     return CE_None;
    1030                 : }
    1031                 : 
    1032                 : /************************************************************************/
    1033                 : /*                          IBuildOverviews()                           */
    1034                 : /************************************************************************/
    1035                 : 
    1036               0 : CPLErr MrSIDDataset::IBuildOverviews( const char *, int, int *,
    1037                 :                                       int, int *, GDALProgressFunc,
    1038                 :                                       void * )
    1039                 : {
    1040                 :   CPLError( CE_Warning, CPLE_AppDefined,
    1041                 :         "MrSID overviews are built-in, so building external "
    1042               0 :         "overviews is unnecessary. Ignoring.\n" );
    1043                 : 
    1044               0 :   return CE_None;
    1045                 : }
    1046                 : 
    1047                 : /************************************************************************/
    1048                 : /*                          GetGeoTransform()                           */
    1049                 : /************************************************************************/
    1050                 : 
    1051               5 : CPLErr MrSIDDataset::GetGeoTransform( double * padfTransform )
    1052                 : {
    1053               5 :     if( (strlen(GDALPamDataset::GetProjectionRef()) > 0 &&
    1054                 :          GDALPamDataset::GetGeoTransform( padfTransform ) == CE_None )
    1055                 :         || !bHasGeoTransform )
    1056                 :     {
    1057               1 :         return GDALPamDataset::GetGeoTransform( padfTransform );
    1058                 :     }
    1059                 :     else
    1060                 :     {
    1061               4 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1062               4 :         return( CE_None );
    1063                 :     }
    1064                 : }
    1065                 : 
    1066                 : /************************************************************************/
    1067                 : /*                          GetProjectionRef()                          */
    1068                 : /************************************************************************/
    1069                 : 
    1070               4 : const char *MrSIDDataset::GetProjectionRef()
    1071                 : {
    1072               4 :     const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
    1073                 : 
    1074               4 :     if( strlen(pszProjection) > 0 && strlen(pszPamPrj) == 0 )
    1075               3 :         return pszProjection;
    1076                 :     else
    1077               1 :         return pszPamPrj;
    1078                 : }
    1079                 : 
    1080                 : /************************************************************************/
    1081                 : /*                        SerializeMetadataRec()                        */
    1082                 : /************************************************************************/
    1083                 : 
    1084             357 : char *MrSIDDataset::SerializeMetadataRec( const LTIMetadataRecord *poMetadataRec )
    1085                 : {
    1086             357 :     GUInt32  iNumDims = 0;
    1087             357 :     const GUInt32  *paiDims = NULL;
    1088             357 :     const void     *pData = poMetadataRec->getArrayData( iNumDims, paiDims );
    1089             357 :     GUInt32        i, j, k = 0, iLength;
    1090             357 :     char           *pszMetadata = CPLStrdup( "" );
    1091                 : 
    1092             714 :     for ( i = 0; i < iNumDims; i++ )
    1093                 :     {
    1094                 :         // stops on large binary data
    1095             357 :         if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_UINT8 
    1096               0 :              && paiDims[i] > 1024 )
    1097               0 :             return pszMetadata;
    1098                 : 
    1099             890 :         for ( j = 0; j < paiDims[i]; j++ )
    1100                 :         {
    1101             533 :             CPLString osTemp;
    1102                 : 
    1103             533 :             switch( poMetadataRec->getDataType() )
    1104                 :             {
    1105                 :                 case LTI_METADATA_DATATYPE_UINT8:
    1106                 :                 case LTI_METADATA_DATATYPE_SINT8:
    1107               0 :                     osTemp.Printf( "%d", ((GByte *)pData)[k++] );
    1108               0 :                     break;
    1109                 :                 case LTI_METADATA_DATATYPE_UINT16:
    1110             115 :                     osTemp.Printf( "%u", ((GUInt16 *)pData)[k++] );
    1111             115 :                     break;
    1112                 :                 case LTI_METADATA_DATATYPE_SINT16:
    1113               0 :                     osTemp.Printf( "%d", ((GInt16 *)pData)[k++] );
    1114               0 :                     break;
    1115                 :                 case LTI_METADATA_DATATYPE_UINT32:
    1116              16 :                     osTemp.Printf( "%u", ((GUInt32 *)pData)[k++] );
    1117              16 :                     break;
    1118                 :                 case LTI_METADATA_DATATYPE_SINT32:
    1119              24 :                     osTemp.Printf( "%d", ((GInt32 *)pData)[k++] );
    1120              24 :                     break;
    1121                 :                 case LTI_METADATA_DATATYPE_FLOAT32:
    1122              24 :                     osTemp.Printf( "%f", ((float *)pData)[k++] );
    1123              24 :                     break;
    1124                 :                 case LTI_METADATA_DATATYPE_FLOAT64:
    1125             225 :                     osTemp.Printf( "%f", ((double *)pData)[k++] );
    1126             225 :                     break;
    1127                 :                 case LTI_METADATA_DATATYPE_ASCII:
    1128             129 :                     osTemp = ((const char **)pData)[k++];
    1129             129 :                     break;
    1130                 :                 default:
    1131               0 :                     osTemp = "";
    1132                 :                     break;
    1133                 :             }
    1134                 : 
    1135             533 :             iLength = strlen(pszMetadata) + strlen(osTemp) + 2;
    1136                 : 
    1137             533 :             pszMetadata = (char *)CPLRealloc( pszMetadata, iLength );
    1138             533 :             if ( !EQUAL( pszMetadata, "" ) )
    1139             176 :                 strncat( pszMetadata, ",", 1 );
    1140             533 :             strncat( pszMetadata, osTemp, iLength );
    1141                 :         }
    1142                 :     }
    1143                 : 
    1144             357 :     return pszMetadata;
    1145                 : }
    1146                 : 
    1147                 : /************************************************************************/
    1148                 : /*                          GetMetadataElement()                        */
    1149                 : /************************************************************************/
    1150                 : 
    1151             469 : int MrSIDDataset::GetMetadataElement( const char *pszKey, void *pValue,
    1152                 :                                       int iLength )
    1153                 : {
    1154             469 :     if ( !poMetadata->has( pszKey ) )
    1155             352 :         return FALSE;
    1156                 : 
    1157             117 :     const LTIMetadataRecord *poMetadataRec = NULL;
    1158             117 :     poMetadata->get( pszKey, poMetadataRec );
    1159                 : 
    1160             117 :     if ( !poMetadataRec->isScalar() )
    1161              32 :         return FALSE;
    1162                 : 
    1163                 :     // XXX: return FALSE if we have more than one element in metadata record
    1164                 :     int iSize;
    1165              85 :     switch( poMetadataRec->getDataType() )
    1166                 :     {
    1167                 :          case LTI_METADATA_DATATYPE_UINT8:
    1168                 :          case LTI_METADATA_DATATYPE_SINT8:
    1169               0 :              iSize = 1;
    1170               0 :              break;
    1171                 :          case LTI_METADATA_DATATYPE_UINT16:
    1172                 :          case LTI_METADATA_DATATYPE_SINT16:
    1173              76 :              iSize = 2;
    1174              76 :              break;
    1175                 :          case LTI_METADATA_DATATYPE_UINT32:
    1176                 :          case LTI_METADATA_DATATYPE_SINT32:
    1177                 :          case LTI_METADATA_DATATYPE_FLOAT32:
    1178               0 :              iSize = 4;
    1179               0 :              break;
    1180                 :          case LTI_METADATA_DATATYPE_FLOAT64:
    1181               0 :              iSize = 8;
    1182               0 :              break;
    1183                 :          case LTI_METADATA_DATATYPE_ASCII:
    1184               9 :              iSize = iLength;
    1185               9 :              break;
    1186                 :          default:
    1187               0 :              iSize = 0;
    1188                 :              break;
    1189                 :     }
    1190                 : 
    1191              85 :     if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_ASCII )
    1192                 :     {
    1193                 :         strncpy( (char *)pValue,
    1194               9 :                  ((const char**)poMetadataRec->getScalarData())[0], iSize );
    1195               9 :         ((char *)pValue)[iSize - 1] = '\0';
    1196                 :     }
    1197                 :     else
    1198              76 :         memcpy( pValue, poMetadataRec->getScalarData(), iSize );
    1199                 : 
    1200              85 :     return TRUE;
    1201                 : }
    1202                 : 
    1203                 : /************************************************************************/
    1204                 : /*                            GetFileList()                             */
    1205                 : /************************************************************************/
    1206                 : 
    1207               1 : char** MrSIDDataset::GetFileList()
    1208                 : {
    1209               1 :     char** papszFileList = GDALPamDataset::GetFileList();
    1210                 : 
    1211               1 :     if (osMETFilename.size() != 0)
    1212               0 :         papszFileList = CSLAddString(papszFileList, osMETFilename.c_str());
    1213                 : 
    1214               1 :     return papszFileList;
    1215                 : }
    1216                 : 
    1217                 : /************************************************************************/
    1218                 : /*                             OpenZoomLevel()                          */
    1219                 : /************************************************************************/
    1220                 : 
    1221             142 : CPLErr MrSIDDataset::OpenZoomLevel( lt_int32 iZoom )
    1222                 : {
    1223                 : /* -------------------------------------------------------------------- */
    1224                 : /*      Get image geometry.                                            */
    1225                 : /* -------------------------------------------------------------------- */
    1226             142 :     if ( iZoom != 0 )
    1227                 :     {
    1228                 :         lt_uint32 iWidth, iHeight;
    1229             115 :         dfCurrentMag = LTIUtils::levelToMag( iZoom );
    1230             115 :         poImageReader->getDimsAtMag( dfCurrentMag, iWidth, iHeight );
    1231             115 :         nRasterXSize = iWidth;
    1232             115 :         nRasterYSize = iHeight;
    1233                 :     }
    1234                 :     else
    1235                 :     {
    1236              27 :         dfCurrentMag = 1.0;
    1237              27 :         nRasterXSize = poImageReader->getWidth();
    1238              27 :         nRasterYSize = poImageReader->getHeight();
    1239                 :     }
    1240                 : 
    1241             142 :     nBands = poImageReader->getNumBands();
    1242             142 :     nBlockXSize = nRasterXSize;
    1243             142 :     nBlockYSize = poImageReader->getStripHeight();
    1244                 : 
    1245                 :     CPLDebug( "MrSID", "Opened zoom level %d with size %dx%d.",
    1246             142 :               iZoom, nRasterXSize, nRasterYSize );
    1247                 : 
    1248                 :     try
    1249                 :     {
    1250             142 :         poLTINav = new LTIDLLNavigator<LTINavigator>( *poImageReader );
    1251                 :     }
    1252               0 :     catch ( ... )
    1253                 :     {
    1254                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1255                 :                   "MrSIDDataset::OpenZoomLevel(): "
    1256               0 :                   "Failed to create LTINavigator object." );
    1257               0 :         return CE_Failure;
    1258                 :     }
    1259                 : 
    1260                 : /* -------------------------------------------------------------------- */
    1261                 : /*  Handle sample type and color space.                                 */
    1262                 : /* -------------------------------------------------------------------- */
    1263             142 :     eColorSpace = poImageReader->getColorSpace();
    1264             142 :     eSampleType = poImageReader->getDataType();
    1265             142 :     switch ( eSampleType )
    1266                 :     {
    1267                 :       case LTI_DATATYPE_UINT16:
    1268              12 :         eDataType = GDT_UInt16;
    1269              12 :         break;
    1270                 :       case LTI_DATATYPE_SINT16:
    1271              12 :         eDataType = GDT_Int16;
    1272              12 :         break;
    1273                 :       case LTI_DATATYPE_UINT32:
    1274               0 :         eDataType = GDT_UInt32;
    1275               0 :         break;
    1276                 :       case LTI_DATATYPE_SINT32:
    1277               0 :         eDataType = GDT_Int32;
    1278               0 :         break;
    1279                 :       case LTI_DATATYPE_FLOAT32:
    1280               0 :         eDataType = GDT_Float32;
    1281               0 :         break;
    1282                 :       case LTI_DATATYPE_FLOAT64:
    1283               0 :         eDataType = GDT_Float64;
    1284               0 :         break;
    1285                 :       case LTI_DATATYPE_UINT8:
    1286                 :       case LTI_DATATYPE_SINT8:
    1287                 :       default:
    1288             118 :         eDataType = GDT_Byte;
    1289                 :         break;
    1290                 :     }
    1291                 : 
    1292                 : /* -------------------------------------------------------------------- */
    1293                 : /*      Read georeferencing.                                            */
    1294                 : /* -------------------------------------------------------------------- */
    1295             142 :     if ( !poImageReader->isGeoCoordImplicit() )
    1296                 :     {
    1297              71 :         const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
    1298                 :         oGeo.get( adfGeoTransform[0], adfGeoTransform[3],
    1299                 :                   adfGeoTransform[1], adfGeoTransform[5],
    1300              71 :                   adfGeoTransform[2], adfGeoTransform[4] );
    1301                 :         
    1302              71 :         adfGeoTransform[0] = adfGeoTransform[0] - adfGeoTransform[1] / 2;
    1303              71 :         adfGeoTransform[3] = adfGeoTransform[3] - adfGeoTransform[5] / 2;
    1304              71 :         bHasGeoTransform = TRUE;
    1305                 :     }
    1306              71 :     else if( iZoom == 0 )
    1307                 :     {
    1308                 :         bHasGeoTransform = 
    1309              13 :             GDALReadWorldFile( GetDescription(), NULL,
    1310                 :                                adfGeoTransform )
    1311              12 :             || GDALReadWorldFile( GetDescription(), ".wld",
    1312              38 :                                   adfGeoTransform );
    1313                 :     }
    1314                 :     
    1315                 : /* -------------------------------------------------------------------- */
    1316                 : /*      Read wkt.                                                       */
    1317                 : /* -------------------------------------------------------------------- */
    1318                 : #ifdef MRSID_HAVE_GETWKT
    1319             142 :     if( !poImageReader->isGeoCoordImplicit() )
    1320                 :     {
    1321              71 :         const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
    1322                 :         
    1323              71 :         if( oGeo.getWKT() )
    1324                 :         {
    1325                 :             /* Workaround probable issue with GeoDSK 7 on 64bit Linux */
    1326              71 :             if (!(pszProjection != NULL && !EQUALN(pszProjection, "LOCAL_CS", 8)
    1327                 :                 && EQUALN( oGeo.getWKT(), "LOCAL_CS", 8)))
    1328                 :             {
    1329              71 :                 CPLFree( pszProjection );
    1330              71 :                 pszProjection =  CPLStrdup( oGeo.getWKT() );
    1331                 :             }
    1332                 :         }
    1333                 :     }
    1334                 : #endif // HAVE_MRSID_GETWKT
    1335                 : 
    1336                 : /* -------------------------------------------------------------------- */
    1337                 : /*      Special case for https://zulu.ssc.nasa.gov/mrsid/mrsid.pl       */
    1338                 : /*      where LandSat .SID are accompanied by a .met file with the      */
    1339                 : /*      projection                                                      */
    1340                 : /* -------------------------------------------------------------------- */
    1341             153 :     if (iZoom == 0 && (pszProjection == NULL || pszProjection[0] == '\0') &&
    1342              11 :         EQUAL(CPLGetExtension(GetDescription()), "sid"))
    1343                 :     {
    1344               0 :         const char* pszMETFilename = CPLResetExtension(GetDescription(), "met");
    1345               0 :         VSILFILE* fp = VSIFOpenL(pszMETFilename, "rb");
    1346               0 :         if (fp)
    1347                 :         {
    1348                 :             const char* pszLine;
    1349               0 :             int nCountLine = 0;
    1350               0 :             int nUTMZone = 0;
    1351               0 :             int bWGS84 = FALSE;
    1352               0 :             int bUnitsMeter = FALSE;
    1353               0 :             while ( (pszLine = CPLReadLine2L(fp, 200, NULL)) != NULL &&
    1354                 :                     ++nCountLine < 1000 )
    1355                 :             {
    1356               0 :                 if (nCountLine == 1 && strcmp(pszLine, "::MetadataFile") != 0)
    1357               0 :                     break;
    1358               0 :                 if (EQUALN(pszLine, "Projection UTM ", 15))
    1359               0 :                     nUTMZone = atoi(pszLine + 15);
    1360               0 :                 else if (EQUAL(pszLine, "Datum WGS84"))
    1361               0 :                     bWGS84 = TRUE;
    1362               0 :                 else if (EQUAL(pszLine, "Units Meters"))
    1363               0 :                     bUnitsMeter = TRUE;
    1364                 :             }
    1365               0 :             VSIFCloseL(fp);
    1366                 : 
    1367                 :             /* Images in southern hemisphere have negative northings in the */
    1368                 :             /* .sdw file. A bit weird, but anyway we must use the northern */
    1369                 :             /* UTM SRS for consistency */
    1370               0 :             if (nUTMZone >= 1 && nUTMZone <= 60 && bWGS84 && bUnitsMeter)
    1371                 :             {
    1372               0 :                 osMETFilename = pszMETFilename;
    1373                 :                 
    1374               0 :                 OGRSpatialReference oSRS;
    1375               0 :                 oSRS.importFromEPSG(32600 + nUTMZone);
    1376               0 :                 CPLFree(pszProjection);
    1377               0 :                 pszProjection = NULL;
    1378               0 :                 oSRS.exportToWkt(&pszProjection);
    1379                 :             }
    1380                 :         }
    1381                 :     }
    1382                 : 
    1383                 : /* -------------------------------------------------------------------- */
    1384                 : /*      Read NoData value.                                              */
    1385                 : /* -------------------------------------------------------------------- */
    1386             142 :     poNDPixel = poImageReader->getNoDataPixel();
    1387                 : 
    1388                 : /* -------------------------------------------------------------------- */
    1389                 : /*      Create band information objects.                                */
    1390                 : /* -------------------------------------------------------------------- */
    1391                 :     int             iBand;
    1392                 : 
    1393             736 :     for( iBand = 1; iBand <= nBands; iBand++ )
    1394             226 :         SetBand( iBand, new MrSIDRasterBand( this, iBand ) );
    1395                 : 
    1396             142 :     return CE_None;
    1397                 : }
    1398                 : 
    1399                 : /************************************************************************/
    1400                 : /*                         MrSIDIdentify()                              */
    1401                 : /*                                                                      */
    1402                 : /*          Identify method that only supports MrSID files.             */
    1403                 : /************************************************************************/
    1404                 : 
    1405           12626 : static int MrSIDIdentify( GDALOpenInfo * poOpenInfo )
    1406                 : {
    1407           12626 :     if( poOpenInfo->nHeaderBytes < 32 )
    1408           11610 :         return FALSE;
    1409                 : 
    1410            1016 :     if ( !EQUALN((const char *) poOpenInfo->pabyHeader, "msid", 4) )
    1411            1007 :         return FALSE;
    1412                 : 
    1413                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    1414                 :     lt_uint8 gen;
    1415                 :     bool raster;
    1416                 :     LT_STATUS eStat =
    1417               9 :         MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
    1418               9 :     if (!LT_SUCCESS(eStat) || !raster)
    1419               0 :        return FALSE;
    1420                 : #endif
    1421                 : 
    1422               9 :     return TRUE;
    1423                 : }
    1424                 : 
    1425                 : /************************************************************************/
    1426                 : /*                          MrSIDOpen()                                 */
    1427                 : /*                                                                      */
    1428                 : /*          Open method that only supports MrSID files.                 */
    1429                 : /************************************************************************/
    1430                 : 
    1431            2533 : static GDALDataset* MrSIDOpen( GDALOpenInfo *poOpenInfo )
    1432                 : {
    1433            2533 :     if (!MrSIDIdentify(poOpenInfo))
    1434            2524 :         return NULL;
    1435                 :         
    1436               9 :     return MrSIDDataset::Open( poOpenInfo, FALSE );
    1437                 : }
    1438                 : 
    1439                 : 
    1440                 : #ifdef MRSID_J2K
    1441                 : 
    1442                 : static const unsigned char jpc_header[] = 
    1443                 : {0xff,0x4f};
    1444                 : 
    1445                 : /************************************************************************/
    1446                 : /*                         JP2Identify()                                */
    1447                 : /*                                                                      */
    1448                 : /*        Identify method that only supports JPEG2000 files.            */
    1449                 : /************************************************************************/
    1450                 : 
    1451           11978 : static int JP2Identify( GDALOpenInfo *poOpenInfo )
    1452                 : {
    1453           11978 :     if( poOpenInfo->nHeaderBytes < 32 )
    1454           11486 :         return FALSE;
    1455                 : 
    1456             492 :     if( memcmp( poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header) ) == 0 )
    1457                 :     {
    1458                 :         const char *pszExtension;
    1459                 : 
    1460               9 :         pszExtension = CPLGetExtension( poOpenInfo->pszFilename );
    1461                 :         
    1462               9 :         if( !EQUAL(pszExtension,"jpc") && !EQUAL(pszExtension,"j2k") 
    1463                 :             && !EQUAL(pszExtension,"jp2") && !EQUAL(pszExtension,"jpx") 
    1464                 :             && !EQUAL(pszExtension,"j2c") && !EQUAL(pszExtension,"ntf"))
    1465               0 :             return FALSE;
    1466                 :     }
    1467             483 :     else if( !EQUALN((const char *) poOpenInfo->pabyHeader + 4, "jP  ", 4) )
    1468             474 :         return FALSE;
    1469                 : 
    1470              18 :     return TRUE;
    1471                 : }
    1472                 : 
    1473                 : /************************************************************************/
    1474                 : /*                            JP2Open()                                 */
    1475                 : /*                                                                      */
    1476                 : /*      Open method that only supports JPEG2000 files.                  */
    1477                 : /************************************************************************/
    1478                 : 
    1479            1922 : static GDALDataset* JP2Open( GDALOpenInfo *poOpenInfo )
    1480                 : {
    1481            1922 :     if (!JP2Identify(poOpenInfo))
    1482            1904 :         return NULL;
    1483                 :         
    1484              18 :     return MrSIDDataset::Open( poOpenInfo, TRUE );
    1485                 : }
    1486                 : 
    1487                 : #endif // MRSID_J2K
    1488                 : 
    1489                 : /************************************************************************/
    1490                 : /*                                Open()                                */
    1491                 : /************************************************************************/
    1492                 : 
    1493              27 : GDALDataset *MrSIDDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJP2 )
    1494                 : {
    1495              27 :     if(poOpenInfo->fp)
    1496                 :     {
    1497              21 :         VSIFClose( poOpenInfo->fp );
    1498              21 :         poOpenInfo->fp = NULL;
    1499                 :     }
    1500                 : 
    1501                 : /* -------------------------------------------------------------------- */
    1502                 : /*      Create a corresponding GDALDataset.                             */
    1503                 : /* -------------------------------------------------------------------- */
    1504                 :     MrSIDDataset    *poDS;
    1505                 :     LT_STATUS       eStat;
    1506                 : 
    1507              27 :     poDS = new MrSIDDataset(bIsJP2);
    1508                 : 
    1509                 :     // try the LTIOFileStream first, since it uses filesystem caching
    1510              27 :     eStat = poDS->oLTIStream.initialize( poOpenInfo->pszFilename, "rb" );
    1511              27 :     if ( LT_SUCCESS(eStat) )
    1512                 :     {
    1513              27 :         eStat = poDS->oLTIStream.open();
    1514              27 :         if ( LT_SUCCESS(eStat) )
    1515              21 :             poDS->poStream = &(poDS->oLTIStream);
    1516                 :     }
    1517                 : 
    1518                 :     // fall back on VSI for non-files
    1519              27 :     if ( !LT_SUCCESS(eStat) || !poDS->poStream )
    1520                 :     {
    1521               6 :         eStat = poDS->oVSIStream.initialize( poOpenInfo->pszFilename, "rb" );
    1522               6 :         if ( !LT_SUCCESS(eStat) )
    1523                 :         {
    1524                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1525                 :                       "LTIVSIStream::initialize(): "
    1526                 :                       "failed to open file \"%s\".\n%s",
    1527               0 :                       poOpenInfo->pszFilename, getLastStatusString( eStat ) );
    1528               0 :             delete poDS;
    1529               0 :             return NULL;
    1530                 :         }
    1531                 : 
    1532               6 :         eStat = poDS->oVSIStream.open();
    1533               6 :         if ( !LT_SUCCESS(eStat) )
    1534                 :         {
    1535                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1536                 :                       "LTIVSIStream::open(): "
    1537                 :                       "failed to open file \"%s\".\n%s",
    1538               0 :                       poOpenInfo->pszFilename, getLastStatusString( eStat ) );
    1539               0 :             delete poDS;
    1540               0 :             return NULL;
    1541                 :         }
    1542                 : 
    1543               6 :         poDS->poStream = &(poDS->oVSIStream);
    1544                 :     }
    1545                 : 
    1546                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
    1547                 : 
    1548                 : #ifdef MRSID_J2K
    1549              27 :     if ( bIsJP2 )
    1550                 :     {
    1551              18 :         J2KImageReader  *reader = J2KImageReader::create();
    1552              18 :         eStat = reader->initialize( *(poDS->poStream) );
    1553              18 :         poDS->poImageReader = reader;
    1554                 :     }
    1555                 :     else
    1556                 : #endif /* MRSID_J2K */
    1557                 :     {
    1558               9 :         MrSIDImageReader    *reader = MrSIDImageReader::create();
    1559               9 :         eStat = reader->initialize( poDS->poStream, NULL );
    1560               9 :         poDS->poImageReader = reader;           
    1561                 :     }
    1562                 : 
    1563                 : #else /* LTI_SDK_MAJOR < 7 */
    1564                 : 
    1565                 : #ifdef MRSID_J2K
    1566                 :     if ( bIsJP2 )
    1567                 :     {
    1568                 :         poDS->poImageReader =
    1569                 :             new LTIDLLReader<J2KImageReader>( *(poDS->poStream), true );
    1570                 :         eStat = poDS->poImageReader->initialize();
    1571                 :     }
    1572                 :     else
    1573                 : #endif /* MRSID_J2K */
    1574                 :     {
    1575                 :         poDS->poImageReader =
    1576                 :             new LTIDLLReader<MrSIDImageReader>( poDS->poStream, NULL );
    1577                 :         eStat = poDS->poImageReader->initialize();
    1578                 :     }
    1579                 : 
    1580                 : #endif /* LTI_SDK_MAJOR >= 7 */
    1581                 : 
    1582              27 :     if ( !LT_SUCCESS(eStat) )
    1583                 :     {
    1584                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1585                 :                   "LTIImageReader::initialize(): "
    1586                 :                   "failed to initialize reader from the stream \"%s\".\n%s",
    1587               0 :                   poOpenInfo->pszFilename, getLastStatusString( eStat ) );
    1588               0 :         delete poDS;
    1589               0 :         return NULL;
    1590                 :     }
    1591                 : 
    1592                 : /* -------------------------------------------------------------------- */
    1593                 : /*      Read metadata.                                                  */
    1594                 : /* -------------------------------------------------------------------- */
    1595                 :     poDS->poMetadata = new LTIDLLCopy<LTIMetadataDatabase>(
    1596              27 :         poDS->poImageReader->getMetadata() );
    1597              27 :     const GUInt32       iNumRecs = poDS->poMetadata->getIndexCount();
    1598                 :     GUInt32             i;
    1599                 : 
    1600             384 :     for ( i = 0; i < iNumRecs; i++ )
    1601                 :     {
    1602             357 :         const LTIMetadataRecord *poMetadataRec = NULL;
    1603             357 :         if ( LT_SUCCESS(poDS->poMetadata->getDataByIndex(i, poMetadataRec)) )
    1604                 :         {
    1605             357 :             char    *pszElement = poDS->SerializeMetadataRec( poMetadataRec );
    1606             357 :             char    *pszKey = CPLStrdup( poMetadataRec->getTagName() );
    1607             357 :             char    *pszTemp = pszKey;
    1608                 : 
    1609                 :             // GDAL metadata keys should not contain ':' and '=' characters.
    1610                 :             // We will replace them with '_'.
    1611           11711 :             do
    1612                 :             {
    1613           11711 :                 if ( *pszTemp == ':' || *pszTemp == '=' )
    1614            1020 :                     *pszTemp = '_';
    1615                 :             }
    1616                 :             while ( *++pszTemp );
    1617                 : 
    1618             357 :             poDS->SetMetadataItem( pszKey, pszElement );
    1619                 : 
    1620             357 :             CPLFree( pszElement );
    1621             357 :             CPLFree( pszKey );
    1622                 :         }
    1623                 :     }
    1624                 : 
    1625                 : /* -------------------------------------------------------------------- */
    1626                 : /*      Add MrSID version.                                              */
    1627                 : /* -------------------------------------------------------------------- */
    1628                 : #ifdef MRSID_J2K
    1629              27 :     if( !bIsJP2 )
    1630                 : #endif
    1631                 :     {
    1632                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    1633                 :         lt_uint8 gen;
    1634                 :         bool raster;
    1635               9 :         MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
    1636               9 :         poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d%s", gen, raster ? "" : " LiDAR") );
    1637                 : #else
    1638                 :         lt_uint8 major;
    1639                 :         lt_uint8 minor;
    1640                 :         char letter;
    1641                 :         MrSIDImageReader* poMrSIDImageReader = (MrSIDImageReader*)poDS->poImageReader;
    1642                 :         poMrSIDImageReader->getVersion(major, minor, minor, letter);
    1643                 :         if (major < 2) 
    1644                 :             major = 2;
    1645                 :         poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d", major) );
    1646                 : #endif
    1647                 :     }
    1648                 : 
    1649              27 :     poDS->GetGTIFDefn();
    1650                 :     
    1651                 : /* -------------------------------------------------------------------- */
    1652                 : /*      Get number of resolution levels (we will use them as overviews).*/
    1653                 : /* -------------------------------------------------------------------- */
    1654                 : #ifdef MRSID_J2K
    1655              27 :     if( bIsJP2 )
    1656                 :         poDS->nOverviewCount
    1657              18 :             = ((J2KImageReader *) (poDS->poImageReader))->getNumLevels();
    1658                 :     else
    1659                 : #endif
    1660                 :         poDS->nOverviewCount
    1661               9 :             = ((MrSIDImageReader *) (poDS->poImageReader))->getNumLevels();
    1662                 : 
    1663              27 :     if ( poDS->nOverviewCount > 0 )
    1664                 :     {
    1665                 :         lt_int32        i;
    1666                 : 
    1667                 :         poDS->papoOverviewDS = (MrSIDDataset **)
    1668              25 :             CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) );
    1669                 : 
    1670             280 :         for ( i = 0; i < poDS->nOverviewCount; i++ )
    1671                 :         {
    1672             115 :             poDS->papoOverviewDS[i] = new MrSIDDataset(bIsJP2);
    1673             115 :             poDS->papoOverviewDS[i]->poImageReader = poDS->poImageReader;
    1674             115 :             poDS->papoOverviewDS[i]->OpenZoomLevel( i + 1 );
    1675             115 :             poDS->papoOverviewDS[i]->bIsOverview = TRUE;
    1676             115 :             poDS->papoOverviewDS[i]->poParentDS = poDS;
    1677                 :         }
    1678                 :     }
    1679                 : 
    1680                 : /* -------------------------------------------------------------------- */
    1681                 : /*      Create object for the whole image.                              */
    1682                 : /* -------------------------------------------------------------------- */
    1683              27 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1684              27 :     poDS->OpenZoomLevel( 0 );
    1685                 : 
    1686                 :     CPLDebug( "MrSID",
    1687                 :               "Opened image: width %d, height %d, bands %d",
    1688              27 :               poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands );
    1689                 : 
    1690              27 :     if( poDS->nBands > 1 )
    1691               7 :         poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    1692                 : 
    1693              27 :     if (bIsJP2)
    1694                 :     {
    1695              18 :         GDALJP2Metadata oJP2Geo;
    1696              18 :         if ( oJP2Geo.ReadAndParse( poOpenInfo->pszFilename ) )
    1697                 :         {
    1698                 :             /*poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
    1699                 :             poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
    1700                 :             memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
    1701                 :                     sizeof(double) * 6 );
    1702                 :             poDS->nGCPCount = oJP2Geo.nGCPCount;
    1703                 :             poDS->pasGCPList = oJP2Geo.pasGCPList;
    1704                 :             oJP2Geo.pasGCPList = NULL;
    1705                 :             oJP2Geo.nGCPCount = 0;*/
    1706                 :         }
    1707                 : 
    1708              18 :         if (oJP2Geo.pszXMPMetadata)
    1709                 :         {
    1710                 :             char *apszMDList[2];
    1711               1 :             apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
    1712               1 :             apszMDList[1] = NULL;
    1713               1 :             poDS->SetMetadata(apszMDList, "xml:XMP");
    1714              18 :         }
    1715                 :     }
    1716                 : 
    1717                 : /* -------------------------------------------------------------------- */
    1718                 : /*      Initialize any PAM information.                                 */
    1719                 : /* -------------------------------------------------------------------- */
    1720              27 :     poDS->TryLoadXML();
    1721                 : 
    1722                 : /* -------------------------------------------------------------------- */
    1723                 : /*      Initialize the overview manager for mask band support.          */
    1724                 : /* -------------------------------------------------------------------- */
    1725              27 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    1726                 : 
    1727              27 :     return( poDS );
    1728                 : }
    1729                 : 
    1730                 : /************************************************************************/
    1731                 : /*                    EPSGProjMethodToCTProjMethod()                    */
    1732                 : /*                                                                      */
    1733                 : /*      Convert between the EPSG enumeration for projection methods,    */
    1734                 : /*      and the GeoTIFF CT codes.                                       */
    1735                 : /*      Explicitly copied from geo_normalize.c of the GeoTIFF package   */
    1736                 : /************************************************************************/
    1737                 : 
    1738               5 : static int EPSGProjMethodToCTProjMethod( int nEPSG )
    1739                 : 
    1740                 : {
    1741                 :     /* see trf_method.csv for list of EPSG codes */
    1742                 :     
    1743               5 :     switch( nEPSG )
    1744                 :     {
    1745                 :       case 9801:
    1746               0 :         return( CT_LambertConfConic_1SP );
    1747                 : 
    1748                 :       case 9802:
    1749               0 :         return( CT_LambertConfConic_2SP );
    1750                 : 
    1751                 :       case 9803:
    1752               0 :         return( CT_LambertConfConic_2SP ); /* Belgian variant not supported */
    1753                 : 
    1754                 :       case 9804:
    1755               0 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
    1756                 : 
    1757                 :       case 9805:
    1758               0 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
    1759                 : 
    1760                 :       case 9806:
    1761               0 :         return( CT_CassiniSoldner );
    1762                 : 
    1763                 :       case 9807:
    1764               5 :         return( CT_TransverseMercator );
    1765                 : 
    1766                 :       case 9808:
    1767               0 :         return( CT_TransvMercator_SouthOriented );
    1768                 : 
    1769                 :       case 9809:
    1770               0 :         return( CT_ObliqueStereographic );
    1771                 : 
    1772                 :       case 9810:
    1773               0 :         return( CT_PolarStereographic );
    1774                 : 
    1775                 :       case 9811:
    1776               0 :         return( CT_NewZealandMapGrid );
    1777                 : 
    1778                 :       case 9812:
    1779               0 :         return( CT_ObliqueMercator ); /* is hotine actually different? */
    1780                 : 
    1781                 :       case 9813:
    1782               0 :         return( CT_ObliqueMercator_Laborde );
    1783                 : 
    1784                 :       case 9814:
    1785               0 :         return( CT_ObliqueMercator_Rosenmund ); /* swiss  */
    1786                 : 
    1787                 :       case 9815:
    1788               0 :         return( CT_ObliqueMercator );
    1789                 : 
    1790                 :       case 9816: /* tunesia mining grid has no counterpart */
    1791               0 :         return( KvUserDefined );
    1792                 :     }
    1793                 : 
    1794               0 :     return( KvUserDefined );
    1795                 : }
    1796                 : 
    1797                 : /* EPSG Codes for projection parameters.  Unfortunately, these bear no
    1798                 :    relationship to the GeoTIFF codes even though the names are so similar. */
    1799                 : 
    1800                 : #define EPSGNatOriginLat         8801
    1801                 : #define EPSGNatOriginLong        8802
    1802                 : #define EPSGNatOriginScaleFactor 8805
    1803                 : #define EPSGFalseEasting         8806
    1804                 : #define EPSGFalseNorthing        8807
    1805                 : #define EPSGProjCenterLat        8811
    1806                 : #define EPSGProjCenterLong       8812
    1807                 : #define EPSGAzimuth              8813
    1808                 : #define EPSGAngleRectifiedToSkewedGrid 8814
    1809                 : #define EPSGInitialLineScaleFactor 8815
    1810                 : #define EPSGProjCenterEasting    8816
    1811                 : #define EPSGProjCenterNorthing   8817
    1812                 : #define EPSGPseudoStdParallelLat 8818
    1813                 : #define EPSGPseudoStdParallelScaleFactor 8819
    1814                 : #define EPSGFalseOriginLat       8821
    1815                 : #define EPSGFalseOriginLong      8822
    1816                 : #define EPSGStdParallel1Lat      8823
    1817                 : #define EPSGStdParallel2Lat      8824
    1818                 : #define EPSGFalseOriginEasting   8826
    1819                 : #define EPSGFalseOriginNorthing  8827
    1820                 : #define EPSGSphericalOriginLat   8828
    1821                 : #define EPSGSphericalOriginLong  8829
    1822                 : #define EPSGInitialLongitude     8830
    1823                 : #define EPSGZoneWidth            8831
    1824                 : 
    1825                 : /************************************************************************/
    1826                 : /*                            SetGTParmIds()                            */
    1827                 : /*                                                                      */
    1828                 : /*      This is hardcoded logic to set the GeoTIFF parameter            */
    1829                 : /*      identifiers for all the EPSG supported projections.  As the     */
    1830                 : /*      trf_method.csv table grows with new projections, this code      */
    1831                 : /*      will need to be updated.                                        */
    1832                 : /*      Explicitly copied from geo_normalize.c of the GeoTIFF package.  */
    1833                 : /************************************************************************/
    1834                 : 
    1835               5 : static int SetGTParmIds( int nCTProjection, 
    1836                 :                          int *panProjParmId, 
    1837                 :                          int *panEPSGCodes )
    1838                 : 
    1839                 : {
    1840                 :     int anWorkingDummy[7];
    1841                 : 
    1842               5 :     if( panEPSGCodes == NULL )
    1843               5 :         panEPSGCodes = anWorkingDummy;
    1844               5 :     if( panProjParmId == NULL )
    1845               0 :         panProjParmId = anWorkingDummy;
    1846                 : 
    1847               5 :     memset( panEPSGCodes, 0, sizeof(int) * 7 );
    1848                 : 
    1849                 :     /* psDefn->nParms = 7; */
    1850                 :     
    1851               5 :     switch( nCTProjection )
    1852                 :     {
    1853                 :       case CT_CassiniSoldner:
    1854                 :       case CT_NewZealandMapGrid:
    1855               0 :         panProjParmId[0] = ProjNatOriginLatGeoKey;
    1856               0 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1857               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1858               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1859                 : 
    1860               0 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1861               0 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1862               0 :         panEPSGCodes[5] = EPSGFalseEasting;
    1863               0 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1864               0 :         return TRUE;
    1865                 : 
    1866                 :       case CT_ObliqueMercator:
    1867               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1868               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1869               0 :         panProjParmId[2] = ProjAzimuthAngleGeoKey;
    1870               0 :         panProjParmId[3] = ProjRectifiedGridAngleGeoKey;
    1871               0 :         panProjParmId[4] = ProjScaleAtCenterGeoKey;
    1872               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1873               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1874                 : 
    1875               0 :         panEPSGCodes[0] = EPSGProjCenterLat;
    1876               0 :         panEPSGCodes[1] = EPSGProjCenterLong;
    1877               0 :         panEPSGCodes[2] = EPSGAzimuth;
    1878               0 :         panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
    1879               0 :         panEPSGCodes[4] = EPSGInitialLineScaleFactor;
    1880               0 :         panEPSGCodes[5] = EPSGProjCenterEasting;
    1881               0 :         panEPSGCodes[6] = EPSGProjCenterNorthing;
    1882               0 :         return TRUE;
    1883                 : 
    1884                 :       case CT_ObliqueMercator_Laborde:
    1885               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1886               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1887               0 :         panProjParmId[2] = ProjAzimuthAngleGeoKey;
    1888               0 :         panProjParmId[4] = ProjScaleAtCenterGeoKey;
    1889               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1890               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1891                 : 
    1892               0 :         panEPSGCodes[0] = EPSGProjCenterLat;
    1893               0 :         panEPSGCodes[1] = EPSGProjCenterLong;
    1894               0 :         panEPSGCodes[2] = EPSGAzimuth;
    1895               0 :         panEPSGCodes[4] = EPSGInitialLineScaleFactor;
    1896               0 :         panEPSGCodes[5] = EPSGProjCenterEasting;
    1897               0 :         panEPSGCodes[6] = EPSGProjCenterNorthing;
    1898               0 :         return TRUE;
    1899                 :         
    1900                 :       case CT_LambertConfConic_1SP:
    1901                 :       case CT_Mercator:
    1902                 :       case CT_ObliqueStereographic:
    1903                 :       case CT_PolarStereographic:
    1904                 :       case CT_TransverseMercator:
    1905                 :       case CT_TransvMercator_SouthOriented:
    1906               5 :         panProjParmId[0] = ProjNatOriginLatGeoKey;
    1907               5 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1908               5 :         panProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1909               5 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1910               5 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1911                 : 
    1912               5 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1913               5 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1914               5 :         panEPSGCodes[4] = EPSGNatOriginScaleFactor;
    1915               5 :         panEPSGCodes[5] = EPSGFalseEasting;
    1916               5 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1917               5 :         return TRUE;
    1918                 : 
    1919                 :       case CT_LambertConfConic_2SP:
    1920               0 :         panProjParmId[0] = ProjFalseOriginLatGeoKey;
    1921               0 :         panProjParmId[1] = ProjFalseOriginLongGeoKey;
    1922               0 :         panProjParmId[2] = ProjStdParallel1GeoKey;
    1923               0 :         panProjParmId[3] = ProjStdParallel2GeoKey;
    1924               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1925               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1926                 : 
    1927               0 :         panEPSGCodes[0] = EPSGFalseOriginLat;
    1928               0 :         panEPSGCodes[1] = EPSGFalseOriginLong;
    1929               0 :         panEPSGCodes[2] = EPSGStdParallel1Lat;
    1930               0 :         panEPSGCodes[3] = EPSGStdParallel2Lat;
    1931               0 :         panEPSGCodes[5] = EPSGFalseOriginEasting;
    1932               0 :         panEPSGCodes[6] = EPSGFalseOriginNorthing;
    1933               0 :         return TRUE;
    1934                 : 
    1935                 :       case CT_SwissObliqueCylindrical:
    1936               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1937               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1938               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1939               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1940                 : 
    1941                 :         /* EPSG codes? */
    1942               0 :         return TRUE;
    1943                 : 
    1944                 :       default:
    1945               0 :         return( FALSE );
    1946                 :     }
    1947                 : }
    1948                 : 
    1949                 : static const char *papszDatumEquiv[] =
    1950                 : {
    1951                 :     "Militar_Geographische_Institut",
    1952                 :     "Militar_Geographische_Institute",
    1953                 :     "World_Geodetic_System_1984",
    1954                 :     "WGS_1984",
    1955                 :     "WGS_72_Transit_Broadcast_Ephemeris",
    1956                 :     "WGS_1972_Transit_Broadcast_Ephemeris",
    1957                 :     "World_Geodetic_System_1972",
    1958                 :     "WGS_1972",
    1959                 :     "European_Terrestrial_Reference_System_89",
    1960                 :     "European_Reference_System_1989",
    1961                 :     NULL
    1962                 : };
    1963                 : 
    1964                 : /************************************************************************/
    1965                 : /*                          WKTMassageDatum()                           */
    1966                 : /*                                                                      */
    1967                 : /*      Massage an EPSG datum name into WMT format.  Also transform     */
    1968                 : /*      specific exception cases into WKT versions.                     */
    1969                 : /*      Explicitly copied from the gt_wkt_srs.cpp.                      */
    1970                 : /************************************************************************/
    1971                 : 
    1972              15 : static void WKTMassageDatum( char ** ppszDatum )
    1973                 : 
    1974                 : {
    1975                 :     int         i, j;
    1976              15 :     char        *pszDatum = *ppszDatum;
    1977                 : 
    1978              15 :     if (pszDatum[0] == '\0')
    1979               0 :         return;
    1980                 : 
    1981                 : /* -------------------------------------------------------------------- */
    1982                 : /*      Translate non-alphanumeric values to underscores.               */
    1983                 : /* -------------------------------------------------------------------- */
    1984             392 :     for( i = 0; pszDatum[i] != '\0'; i++ )
    1985                 :     {
    1986            1101 :         if( !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
    1987             559 :             && !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
    1988             165 :             && !(pszDatum[i] >= '0' && pszDatum[i] <= '9') )
    1989                 :         {
    1990              45 :             pszDatum[i] = '_';
    1991                 :         }
    1992                 :     }
    1993                 : 
    1994                 : /* -------------------------------------------------------------------- */
    1995                 : /*      Remove repeated and trailing underscores.                       */
    1996                 : /* -------------------------------------------------------------------- */
    1997             377 :     for( i = 1, j = 0; pszDatum[i] != '\0'; i++ )
    1998                 :     {
    1999             362 :         if( pszDatum[j] == '_' && pszDatum[i] == '_' )
    2000               0 :             continue;
    2001                 : 
    2002             362 :         pszDatum[++j] = pszDatum[i];
    2003                 :     }
    2004              15 :     if( pszDatum[j] == '_' )
    2005               0 :         pszDatum[j] = '\0';
    2006                 :     else
    2007              15 :         pszDatum[j+1] = '\0';
    2008                 :     
    2009                 : /* -------------------------------------------------------------------- */
    2010                 : /*      Search for datum equivelences.  Specific massaged names get     */
    2011                 : /*      mapped to OpenGIS specified names.                              */
    2012                 : /* -------------------------------------------------------------------- */
    2013              82 :     for( i = 0; papszDatumEquiv[i] != NULL; i += 2 )
    2014                 :     {
    2015              69 :         if( EQUAL(*ppszDatum,papszDatumEquiv[i]) )
    2016                 :         {
    2017               2 :             CPLFree( *ppszDatum );
    2018               2 :             *ppszDatum = CPLStrdup( papszDatumEquiv[i+1] );
    2019               2 :             return;
    2020                 :         }
    2021                 :     }
    2022                 : }
    2023                 : 
    2024                 : /************************************************************************/
    2025                 : /*                           FetchProjParms()                           */
    2026                 : /*                                                                      */
    2027                 : /*      Fetch the projection parameters for a particular projection     */
    2028                 : /*      from MrSID metadata, and fill the GTIFDefn structure out        */
    2029                 : /*      with them.                                                      */
    2030                 : /*      Copied from geo_normalize.c of the GeoTIFF package.             */
    2031                 : /************************************************************************/
    2032                 : 
    2033               8 : void MrSIDDataset::FetchProjParms()
    2034                 : {
    2035               8 :     double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
    2036               8 :     double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
    2037               8 :     double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
    2038                 : 
    2039                 : /* -------------------------------------------------------------------- */
    2040                 : /*      Get the false easting, and northing if available.               */
    2041                 : /* -------------------------------------------------------------------- */
    2042               8 :     if( !GetMetadataElement( "GEOTIFF_NUM::3082::ProjFalseEastingGeoKey",
    2043                 :                              &dfFalseEasting )
    2044                 :         && !GetMetadataElement( "GEOTIFF_NUM::3090:ProjCenterEastingGeoKey",
    2045                 :                                 &dfFalseEasting ) )
    2046               8 :         dfFalseEasting = 0.0;
    2047                 :         
    2048               8 :     if( !GetMetadataElement( "GEOTIFF_NUM::3083::ProjFalseNorthingGeoKey",
    2049                 :                              &dfFalseNorthing )
    2050                 :         && !GetMetadataElement( "GEOTIFF_NUM::3091::ProjCenterNorthingGeoKey",
    2051                 :                                 &dfFalseNorthing ) )
    2052               8 :         dfFalseNorthing = 0.0;
    2053                 : 
    2054               8 :     switch( psDefn->CTProjection )
    2055                 :     {
    2056                 : /* -------------------------------------------------------------------- */
    2057                 :       case CT_Stereographic:
    2058                 : /* -------------------------------------------------------------------- */
    2059               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2060                 :                                 &dfNatOriginLong ) == 0
    2061                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2062                 :                                    &dfNatOriginLong ) == 0
    2063                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
    2064                 :                                    &dfNatOriginLong ) == 0 )
    2065               0 :             dfNatOriginLong = 0.0;
    2066                 : 
    2067               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2068                 :                                 &dfNatOriginLat ) == 0
    2069                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2070                 :                                    &dfNatOriginLat ) == 0
    2071                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2072                 :                                    &dfNatOriginLat ) == 0 )
    2073               0 :             dfNatOriginLat = 0.0;
    2074                 : 
    2075               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2076                 :                                 &dfNatOriginScale ) == 0 )
    2077               0 :             dfNatOriginScale = 1.0;
    2078                 :             
    2079                 :         /* notdef: should transform to decimal degrees at this point */
    2080                 : 
    2081               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2082               0 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    2083               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2084               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2085               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2086               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2087               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2088               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2089               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2090               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2091                 : 
    2092               0 :         psDefn->nParms = 7;
    2093               0 :         break;
    2094                 : 
    2095                 : /* -------------------------------------------------------------------- */
    2096                 :       case CT_LambertConfConic_1SP:
    2097                 :       case CT_Mercator:
    2098                 :       case CT_ObliqueStereographic:
    2099                 :       case CT_TransverseMercator:
    2100                 :       case CT_TransvMercator_SouthOriented:
    2101                 : /* -------------------------------------------------------------------- */
    2102               8 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2103                 :                                 &dfNatOriginLong ) == 0
    2104                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2105                 :                                    &dfNatOriginLong ) == 0
    2106                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2107                 :                                    &dfNatOriginLong ) == 0 )
    2108               8 :             dfNatOriginLong = 0.0;
    2109                 : 
    2110               8 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2111                 :                                 &dfNatOriginLat ) == 0
    2112                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2113                 :                                    &dfNatOriginLat ) == 0
    2114                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2115                 :                                    &dfNatOriginLat ) == 0 )
    2116               8 :             dfNatOriginLat = 0.0;
    2117                 : 
    2118               8 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2119                 :                                 &dfNatOriginScale ) == 0 )
    2120               8 :             dfNatOriginScale = 1.0;
    2121                 : 
    2122                 :         /* notdef: should transform to decimal degrees at this point */
    2123                 : 
    2124               8 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2125               8 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2126               8 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2127               8 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2128               8 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2129               8 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2130               8 :         psDefn->ProjParm[5] = dfFalseEasting;
    2131               8 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2132               8 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2133               8 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2134                 : 
    2135               8 :         psDefn->nParms = 7;
    2136               8 :         break;
    2137                 : 
    2138                 : /* -------------------------------------------------------------------- */
    2139                 :       case CT_ObliqueMercator: /* hotine */
    2140                 : /* -------------------------------------------------------------------- */
    2141               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2142                 :                                 &dfNatOriginLong ) == 0
    2143                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2144                 :                                    &dfNatOriginLong ) == 0
    2145                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2146                 :                                    &dfNatOriginLong ) == 0 )
    2147               0 :             dfNatOriginLong = 0.0;
    2148                 : 
    2149               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2150                 :                                 &dfNatOriginLat ) == 0
    2151                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2152                 :                                    &dfNatOriginLat ) == 0
    2153                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2154                 :                                    &dfNatOriginLat ) == 0 )
    2155               0 :             dfNatOriginLat = 0.0;
    2156                 : 
    2157               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3094::ProjAzimuthAngleGeoKey",
    2158                 :                                 &dfAzimuth ) == 0 )
    2159               0 :             dfAzimuth = 0.0;
    2160                 : 
    2161               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3096::ProjRectifiedGridAngleGeoKey",
    2162                 :                                 &dfRectGridAngle ) == 0 )
    2163               0 :             dfRectGridAngle = 90.0;
    2164                 : 
    2165               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2166                 :                                 &dfNatOriginScale ) == 0
    2167                 :             && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
    2168                 :                                    &dfNatOriginScale ) == 0 )
    2169               0 :             dfNatOriginScale = 1.0;
    2170                 :             
    2171                 :         /* notdef: should transform to decimal degrees at this point */
    2172                 : 
    2173               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2174               0 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    2175               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2176               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2177               0 :         psDefn->ProjParm[2] = dfAzimuth;
    2178               0 :         psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
    2179               0 :         psDefn->ProjParm[3] = dfRectGridAngle;
    2180               0 :         psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
    2181               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2182               0 :         psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
    2183               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2184               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2185               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2186               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2187                 : 
    2188               0 :         psDefn->nParms = 7;
    2189               0 :         break;
    2190                 : 
    2191                 : /* -------------------------------------------------------------------- */
    2192                 :       case CT_CassiniSoldner:
    2193                 :       case CT_Polyconic:
    2194                 : /* -------------------------------------------------------------------- */
    2195               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2196                 :                                 &dfNatOriginLong ) == 0
    2197                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2198                 :                                    &dfNatOriginLong ) == 0
    2199                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2200                 :                                    &dfNatOriginLong ) == 0 )
    2201               0 :             dfNatOriginLong = 0.0;
    2202                 : 
    2203               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2204                 :                                 &dfNatOriginLat ) == 0
    2205                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2206                 :                                    &dfNatOriginLat ) == 0
    2207                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2208                 :                                    &dfNatOriginLat ) == 0 )
    2209               0 :             dfNatOriginLat = 0.0;
    2210                 : 
    2211                 : 
    2212               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2213                 :                                 &dfNatOriginScale ) == 0
    2214                 :             && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
    2215                 :                                    &dfNatOriginScale ) == 0 )
    2216               0 :             dfNatOriginScale = 1.0;
    2217                 :             
    2218                 :         /* notdef: should transform to decimal degrees at this point */
    2219                 : 
    2220               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2221               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2222               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2223               0 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2224               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2225               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2226               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2227               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2228               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2229               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2230                 : 
    2231               0 :         psDefn->nParms = 7;
    2232               0 :         break;
    2233                 : 
    2234                 : /* -------------------------------------------------------------------- */
    2235                 :       case CT_AzimuthalEquidistant:
    2236                 :       case CT_MillerCylindrical:
    2237                 :       case CT_Equirectangular:
    2238                 :       case CT_Gnomonic:
    2239                 :       case CT_LambertAzimEqualArea:
    2240                 :       case CT_Orthographic:
    2241                 : /* -------------------------------------------------------------------- */
    2242               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2243                 :                                 &dfNatOriginLong ) == 0
    2244                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2245                 :                                    &dfNatOriginLong ) == 0
    2246                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2247                 :                                    &dfNatOriginLong ) == 0 )
    2248               0 :             dfNatOriginLong = 0.0;
    2249                 : 
    2250               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2251                 :                                 &dfNatOriginLat ) == 0
    2252                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2253                 :                                    &dfNatOriginLat ) == 0
    2254                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2255                 :                                    &dfNatOriginLat ) == 0 )
    2256               0 :             dfNatOriginLat = 0.0;
    2257                 : 
    2258                 :         /* notdef: should transform to decimal degrees at this point */
    2259                 : 
    2260               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2261               0 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    2262               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2263               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2264               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2265               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2266               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2267               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2268                 : 
    2269               0 :         psDefn->nParms = 7;
    2270               0 :         break;
    2271                 : 
    2272                 : /* -------------------------------------------------------------------- */
    2273                 :       case CT_Robinson:
    2274                 :       case CT_Sinusoidal:
    2275                 :       case CT_VanDerGrinten:
    2276                 : /* -------------------------------------------------------------------- */
    2277               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2278                 :                                 &dfNatOriginLong ) == 0
    2279                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2280                 :                                    &dfNatOriginLong ) == 0
    2281                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2282                 :                                    &dfNatOriginLong ) == 0 )
    2283               0 :             dfNatOriginLong = 0.0;
    2284                 : 
    2285                 :         /* notdef: should transform to decimal degrees at this point */
    2286                 : 
    2287               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2288               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2289               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2290               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2291               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2292               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2293                 : 
    2294               0 :         psDefn->nParms = 7;
    2295               0 :         break;
    2296                 : 
    2297                 : /* -------------------------------------------------------------------- */
    2298                 :       case CT_PolarStereographic:
    2299                 : /* -------------------------------------------------------------------- */
    2300               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3095::ProjStraightVertPoleLongGeoKey",
    2301                 :                                 &dfNatOriginLong ) == 0
    2302                 :             && GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2303                 :                                    &dfNatOriginLong ) == 0
    2304                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2305                 :                                    &dfNatOriginLong ) == 0
    2306                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
    2307                 :                                    &dfNatOriginLong ) == 0 )
    2308               0 :             dfNatOriginLong = 0.0;
    2309                 : 
    2310               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2311                 :                                 &dfNatOriginLat ) == 0
    2312                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2313                 :                                    &dfNatOriginLat ) == 0
    2314                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2315                 :                                    &dfNatOriginLat ) == 0 )
    2316               0 :             dfNatOriginLat = 0.0;
    2317                 : 
    2318               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2319                 :                                 &dfNatOriginScale ) == 0
    2320                 :             && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
    2321                 :                                    &dfNatOriginScale ) == 0 )
    2322               0 :             dfNatOriginScale = 1.0;
    2323                 :             
    2324                 :         /* notdef: should transform to decimal degrees at this point */
    2325                 : 
    2326               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2327               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;;
    2328               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2329               0 :         psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
    2330               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2331               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2332               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2333               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2334               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2335               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2336                 : 
    2337               0 :         psDefn->nParms = 7;
    2338               0 :         break;
    2339                 : 
    2340                 : /* -------------------------------------------------------------------- */
    2341                 :       case CT_LambertConfConic_2SP:
    2342                 : /* -------------------------------------------------------------------- */
    2343               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
    2344                 :                                 &dfStdParallel1 ) == 0 )
    2345               0 :             dfStdParallel1 = 0.0;
    2346                 : 
    2347               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
    2348                 :                                 &dfStdParallel2 ) == 0 )
    2349               0 :             dfStdParallel1 = 0.0;
    2350                 : 
    2351               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2352                 :                                 &dfNatOriginLong ) == 0
    2353                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2354                 :                                    &dfNatOriginLong ) == 0
    2355                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2356                 :                                    &dfNatOriginLong ) == 0 )
    2357               0 :             dfNatOriginLong = 0.0;
    2358                 : 
    2359               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2360                 :                                 &dfNatOriginLat ) == 0
    2361                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2362                 :                                    &dfNatOriginLat ) == 0
    2363                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2364                 :                                    &dfNatOriginLat ) == 0 )
    2365               0 :             dfNatOriginLat = 0.0;
    2366                 : 
    2367                 :         /* notdef: should transform to decimal degrees at this point */
    2368                 : 
    2369               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2370               0 :         psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
    2371               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2372               0 :         psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
    2373               0 :         psDefn->ProjParm[2] = dfStdParallel1;
    2374               0 :         psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
    2375               0 :         psDefn->ProjParm[3] = dfStdParallel2;
    2376               0 :         psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
    2377               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2378               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2379               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2380               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2381                 : 
    2382               0 :         psDefn->nParms = 7;
    2383               0 :         break;
    2384                 : 
    2385                 : /* -------------------------------------------------------------------- */
    2386                 :       case CT_AlbersEqualArea:
    2387                 :       case CT_EquidistantConic:
    2388                 : /* -------------------------------------------------------------------- */
    2389               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
    2390                 :                                 &dfStdParallel1 ) == 0 )
    2391               0 :             dfStdParallel1 = 0.0;
    2392                 : 
    2393               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
    2394                 :                                 &dfStdParallel2 ) == 0 )
    2395               0 :             dfStdParallel1 = 0.0;
    2396                 : 
    2397               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2398                 :                                 &dfNatOriginLong ) == 0
    2399                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2400                 :                                    &dfNatOriginLong ) == 0
    2401                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2402                 :                                    &dfNatOriginLong ) == 0 )
    2403               0 :             dfNatOriginLong = 0.0;
    2404                 : 
    2405               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2406                 :                                 &dfNatOriginLat ) == 0
    2407                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2408                 :                                    &dfNatOriginLat ) == 0
    2409                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2410                 :                                    &dfNatOriginLat ) == 0 )
    2411               0 :             dfNatOriginLat = 0.0;
    2412                 : 
    2413                 :         /* notdef: should transform to decimal degrees at this point */
    2414                 : 
    2415               0 :         psDefn->ProjParm[0] = dfStdParallel1;
    2416               0 :         psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
    2417               0 :         psDefn->ProjParm[1] = dfStdParallel2;
    2418               0 :         psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
    2419               0 :         psDefn->ProjParm[2] = dfNatOriginLat;
    2420               0 :         psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
    2421               0 :         psDefn->ProjParm[3] = dfNatOriginLong;
    2422               0 :         psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
    2423               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2424               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2425               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2426               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2427                 : 
    2428               0 :         psDefn->nParms = 7;
    2429                 :         break;
    2430                 :     }
    2431               8 : }
    2432                 : 
    2433                 : /************************************************************************/
    2434                 : /*                            GetGTIFDefn()                             */
    2435                 : /*      This function borrowed from the GTIFGetDefn() function.         */
    2436                 : /*      See geo_normalize.c from the GeoTIFF package.                   */
    2437                 : /************************************************************************/
    2438                 : 
    2439              27 : void MrSIDDataset::GetGTIFDefn()
    2440                 : {
    2441                 :     double      dfInvFlattening;
    2442                 : 
    2443                 : /* -------------------------------------------------------------------- */
    2444                 : /*      Initially we default all the information we can.                */
    2445                 : /* -------------------------------------------------------------------- */
    2446              27 :     psDefn = new( GTIFDefn );
    2447              27 :     psDefn->Model = KvUserDefined;
    2448              27 :     psDefn->PCS = KvUserDefined;
    2449              27 :     psDefn->GCS = KvUserDefined;
    2450              27 :     psDefn->UOMLength = KvUserDefined;
    2451              27 :     psDefn->UOMLengthInMeters = 1.0;
    2452              27 :     psDefn->UOMAngle = KvUserDefined;
    2453              27 :     psDefn->UOMAngleInDegrees = 1.0;
    2454              27 :     psDefn->Datum = KvUserDefined;
    2455              27 :     psDefn->Ellipsoid = KvUserDefined;
    2456              27 :     psDefn->SemiMajor = 0.0;
    2457              27 :     psDefn->SemiMinor = 0.0;
    2458              27 :     psDefn->PM = KvUserDefined;
    2459              27 :     psDefn->PMLongToGreenwich = 0.0;
    2460                 : 
    2461              27 :     psDefn->ProjCode = KvUserDefined;
    2462              27 :     psDefn->Projection = KvUserDefined;
    2463              27 :     psDefn->CTProjection = KvUserDefined;
    2464                 : 
    2465              27 :     psDefn->nParms = 0;
    2466             297 :     for( int i = 0; i < MAX_GTIF_PROJPARMS; i++ )
    2467                 :     {
    2468             270 :         psDefn->ProjParm[i] = 0.0;
    2469             270 :         psDefn->ProjParmId[i] = 0;
    2470                 :     }
    2471                 : 
    2472              27 :     psDefn->MapSys = KvUserDefined;
    2473              27 :     psDefn->Zone = 0;
    2474                 : 
    2475                 : /* -------------------------------------------------------------------- */
    2476                 : /*      Try to get the overall model type.                              */
    2477                 : /* -------------------------------------------------------------------- */
    2478                 :     GetMetadataElement( "GEOTIFF_NUM::1024::GTModelTypeGeoKey",
    2479              27 :                         &(psDefn->Model) );
    2480                 : 
    2481                 : /* -------------------------------------------------------------------- */
    2482                 : /*      Try to get a PCS.                                               */
    2483                 : /* -------------------------------------------------------------------- */
    2484              27 :     if( GetMetadataElement( "GEOTIFF_NUM::3072::ProjectedCSTypeGeoKey",
    2485                 :                             &(psDefn->PCS) )
    2486                 :         && psDefn->PCS != KvUserDefined )
    2487                 :     {
    2488                 :         /*
    2489                 :          * Translate this into useful information.
    2490                 :          */
    2491                 :         GTIFGetPCSInfo( psDefn->PCS, NULL, &(psDefn->ProjCode),
    2492               5 :                         &(psDefn->UOMLength), &(psDefn->GCS) );
    2493                 :     }
    2494                 : 
    2495                 : /* -------------------------------------------------------------------- */
    2496                 : /*       If we have the PCS code, but didn't find it in the CSV files   */
    2497                 : /*      (likely because we can't find them) we will try some ``jiffy    */
    2498                 : /*      rules'' for UTM and state plane.                                */
    2499                 : /* -------------------------------------------------------------------- */
    2500              27 :     if( psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined )
    2501                 :     {
    2502                 :         int     nMapSys, nZone;
    2503               0 :         int     nGCS = psDefn->GCS;
    2504                 : 
    2505               0 :         nMapSys = GTIFPCSToMapSys( psDefn->PCS, &nGCS, &nZone );
    2506               0 :         if( nMapSys != KvUserDefined )
    2507                 :         {
    2508               0 :             psDefn->ProjCode = (short) GTIFMapSysToProj( nMapSys, nZone );
    2509               0 :             psDefn->GCS = (short) nGCS;
    2510                 :         }
    2511                 :     }
    2512                 :    
    2513                 : /* -------------------------------------------------------------------- */
    2514                 : /*      If the Proj_ code is specified directly, use that.              */
    2515                 : /* -------------------------------------------------------------------- */
    2516              27 :     if( psDefn->ProjCode == KvUserDefined )
    2517                 :         GetMetadataElement( "GEOTIFF_NUM::3074::ProjectionGeoKey",
    2518              22 :                             &(psDefn->ProjCode) );
    2519                 :     
    2520              27 :     if( psDefn->ProjCode != KvUserDefined )
    2521                 :     {
    2522                 :         /*
    2523                 :          * We have an underlying projection transformation value.  Look
    2524                 :          * this up.  For a PCS of ``WGS 84 / UTM 11'' the transformation
    2525                 :          * would be Transverse Mercator, with a particular set of options.
    2526                 :          * The nProjTRFCode itself would correspond to the name
    2527                 :          * ``UTM zone 11N'', and doesn't include datum info.
    2528                 :          */
    2529                 :         GTIFGetProjTRFInfo( psDefn->ProjCode, NULL, &(psDefn->Projection),
    2530               5 :                             psDefn->ProjParm );
    2531                 :         
    2532                 :         /*
    2533                 :          * Set the GeoTIFF identity of the parameters.
    2534                 :          */
    2535                 :         psDefn->CTProjection = (short)
    2536               5 :             EPSGProjMethodToCTProjMethod( psDefn->Projection );
    2537                 : 
    2538               5 :         SetGTParmIds( psDefn->CTProjection, psDefn->ProjParmId, NULL);
    2539               5 :         psDefn->nParms = 7;
    2540                 :     }
    2541                 : 
    2542                 : /* -------------------------------------------------------------------- */
    2543                 : /*      Try to get a GCS.  If found, it will override any implied by    */
    2544                 : /*      the PCS.                                                        */
    2545                 : /* -------------------------------------------------------------------- */
    2546                 :     GetMetadataElement( "GEOTIFF_NUM::2048::GeographicTypeGeoKey",
    2547              27 :                         &(psDefn->GCS) );
    2548                 : 
    2549                 : /* -------------------------------------------------------------------- */
    2550                 : /*      Derive the datum, and prime meridian from the GCS.              */
    2551                 : /* -------------------------------------------------------------------- */
    2552              27 :     if( psDefn->GCS != KvUserDefined )
    2553                 :     {
    2554                 :         GTIFGetGCSInfo( psDefn->GCS, NULL, &(psDefn->Datum), &(psDefn->PM),
    2555              15 :                         &(psDefn->UOMAngle) );
    2556                 :     }
    2557                 :     
    2558                 : /* -------------------------------------------------------------------- */
    2559                 : /*      Handle the GCS angular units.  GeogAngularUnitsGeoKey           */
    2560                 : /*      overrides the GCS or PCS setting.                               */
    2561                 : /* -------------------------------------------------------------------- */
    2562                 :     GetMetadataElement( "GEOTIFF_NUM::2054::GeogAngularUnitsGeoKey",
    2563              27 :                         &(psDefn->UOMAngle) );
    2564              27 :     if( psDefn->UOMAngle != KvUserDefined )
    2565                 :     {
    2566                 :         GTIFGetUOMAngleInfo( psDefn->UOMAngle, NULL,
    2567              15 :                              &(psDefn->UOMAngleInDegrees) );
    2568                 :     }
    2569                 : 
    2570                 : /* -------------------------------------------------------------------- */
    2571                 : /*      Check for a datum setting, and then use the datum to derive     */
    2572                 : /*      an ellipsoid.                                                   */
    2573                 : /* -------------------------------------------------------------------- */
    2574                 :     GetMetadataElement( "GEOTIFF_NUM::2050::GeogGeodeticDatumGeoKey",
    2575              27 :                         &(psDefn->Datum) );
    2576                 : 
    2577              27 :     if( psDefn->Datum != KvUserDefined )
    2578                 :     {
    2579              15 :         GTIFGetDatumInfo( psDefn->Datum, NULL, &(psDefn->Ellipsoid) );
    2580                 :     }
    2581                 : 
    2582                 : /* -------------------------------------------------------------------- */
    2583                 : /*      Check for an explicit ellipsoid.  Use the ellipsoid to          */
    2584                 : /*      derive the ellipsoid characteristics, if possible.              */
    2585                 : /* -------------------------------------------------------------------- */
    2586                 :     GetMetadataElement( "GEOTIFF_NUM::2056::GeogEllipsoidGeoKey",
    2587              27 :                         &(psDefn->Ellipsoid) );
    2588                 : 
    2589              27 :     if( psDefn->Ellipsoid != KvUserDefined )
    2590                 :     {
    2591                 :         GTIFGetEllipsoidInfo( psDefn->Ellipsoid, NULL,
    2592              15 :                               &(psDefn->SemiMajor), &(psDefn->SemiMinor) );
    2593                 :     }
    2594                 : 
    2595                 : /* -------------------------------------------------------------------- */
    2596                 : /*      Check for overridden ellipsoid parameters.  It would be nice    */
    2597                 : /*      to warn if they conflict with provided information, but for     */
    2598                 : /*      now we just override.                                           */
    2599                 : /* -------------------------------------------------------------------- */
    2600                 :     GetMetadataElement( "GEOTIFF_NUM::2057::GeogSemiMajorAxisGeoKey",
    2601              27 :                         &(psDefn->SemiMajor) );
    2602                 :     GetMetadataElement( "GEOTIFF_NUM::2058::GeogSemiMinorAxisGeoKey",
    2603              27 :                         &(psDefn->SemiMinor) );
    2604                 :     
    2605              27 :     if( GetMetadataElement( "GEOTIFF_NUM::2059::GeogInvFlatteningGeoKey",
    2606                 :                             &dfInvFlattening ) == 1 )
    2607                 :     {
    2608               0 :         if( dfInvFlattening != 0.0 )
    2609                 :             psDefn->SemiMinor = 
    2610               0 :                 psDefn->SemiMajor * (1 - 1.0/dfInvFlattening);
    2611                 :     }
    2612                 : 
    2613                 : /* -------------------------------------------------------------------- */
    2614                 : /*      Get the prime meridian info.                                    */
    2615                 : /* -------------------------------------------------------------------- */
    2616                 :     GetMetadataElement( "GEOTIFF_NUM::2051::GeogPrimeMeridianGeoKey",
    2617              27 :                         &(psDefn->PM) );
    2618                 : 
    2619              27 :     if( psDefn->PM != KvUserDefined )
    2620                 :     {
    2621              15 :         GTIFGetPMInfo( psDefn->PM, NULL, &(psDefn->PMLongToGreenwich) );
    2622                 :     }
    2623                 :     else
    2624                 :     {
    2625                 :         GetMetadataElement( "GEOTIFF_NUM::2061::GeogPrimeMeridianLongGeoKey",
    2626              12 :                             &(psDefn->PMLongToGreenwich) );
    2627                 : 
    2628                 :         psDefn->PMLongToGreenwich =
    2629                 :             GTIFAngleToDD( psDefn->PMLongToGreenwich,
    2630              12 :                            psDefn->UOMAngle );
    2631                 :     }
    2632                 : 
    2633                 : /* -------------------------------------------------------------------- */
    2634                 : /*      Have the projection units of measure been overridden?  We       */
    2635                 : /*      should likely be doing something about angular units too,       */
    2636                 : /*      but these are very rarely not decimal degrees for actual        */
    2637                 : /*      file coordinates.                                               */
    2638                 : /* -------------------------------------------------------------------- */
    2639                 :     GetMetadataElement( "GEOTIFF_NUM::3076::ProjLinearUnitsGeoKey",
    2640              27 :                         &(psDefn->UOMLength) );
    2641                 : 
    2642              27 :     if( psDefn->UOMLength != KvUserDefined )
    2643                 :     {
    2644                 :         GTIFGetUOMLengthInfo( psDefn->UOMLength, NULL,
    2645              13 :                               &(psDefn->UOMLengthInMeters) );
    2646                 :     }
    2647                 : 
    2648                 : /* -------------------------------------------------------------------- */
    2649                 : /*      Handle a variety of user defined transform types.               */
    2650                 : /* -------------------------------------------------------------------- */
    2651              27 :     if( GetMetadataElement( "GEOTIFF_NUM::3075::ProjCoordTransGeoKey",
    2652                 :                             &(psDefn->CTProjection) ) )
    2653                 :     {
    2654               8 :         FetchProjParms();
    2655                 :     }
    2656                 : 
    2657                 : /* -------------------------------------------------------------------- */
    2658                 : /*      Try to set the zoned map system information.                    */
    2659                 : /* -------------------------------------------------------------------- */
    2660              27 :     psDefn->MapSys = GTIFProjToMapSys( psDefn->ProjCode, &(psDefn->Zone) );
    2661                 : 
    2662                 : /* -------------------------------------------------------------------- */
    2663                 : /*      If this is UTM, and we were unable to extract the projection    */
    2664                 : /*      parameters from the CSV file, just set them directly now,       */
    2665                 : /*      since it's pretty easy, and a common case.                      */
    2666                 : /* -------------------------------------------------------------------- */
    2667              27 :     if( (psDefn->MapSys == MapSys_UTM_North
    2668                 :          || psDefn->MapSys == MapSys_UTM_South)
    2669                 :         && psDefn->CTProjection == KvUserDefined )
    2670                 :     {
    2671               0 :         psDefn->CTProjection = CT_TransverseMercator;
    2672               0 :         psDefn->nParms = 7;
    2673               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2674               0 :         psDefn->ProjParm[0] = 0.0;
    2675                 :             
    2676               0 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2677               0 :         psDefn->ProjParm[1] = psDefn->Zone*6 - 183.0;
    2678                 :         
    2679               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2680               0 :         psDefn->ProjParm[4] = 0.9996;
    2681                 :         
    2682               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2683               0 :         psDefn->ProjParm[5] = 500000.0;
    2684                 :         
    2685               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2686                 : 
    2687               0 :         if( psDefn->MapSys == MapSys_UTM_North )
    2688               0 :             psDefn->ProjParm[6] = 0.0;
    2689                 :         else
    2690               0 :             psDefn->ProjParm[6] = 10000000.0;
    2691                 :     }
    2692                 : 
    2693              27 :     if ( pszProjection )
    2694              27 :         CPLFree( pszProjection );
    2695              27 :     pszProjection = GetOGISDefn( psDefn );
    2696              27 : }
    2697                 : 
    2698                 : 
    2699                 : /************************************************************************/
    2700                 : /*                       GTIFToCPLRecyleString()                        */
    2701                 : /*                                                                      */
    2702                 : /*      This changes a string from the libgeotiff heap to the GDAL      */
    2703                 : /*      heap.                                                           */
    2704                 : /************************************************************************/
    2705                 : 
    2706              74 : static void GTIFToCPLRecycleString( char **ppszTarget )
    2707                 : 
    2708                 : {
    2709              74 :     if( *ppszTarget == NULL )
    2710               0 :         return;
    2711                 : 
    2712              74 :     char *pszTempString = CPLStrdup(*ppszTarget);
    2713              74 :     GTIFFreeMemory( *ppszTarget );
    2714              74 :     *ppszTarget = pszTempString;
    2715                 : }
    2716                 : 
    2717                 : /************************************************************************/
    2718                 : /*                          GetOGISDefn()                               */
    2719                 : /*  Copied from the gt_wkt_srs.cpp.                                     */
    2720                 : /************************************************************************/
    2721                 : 
    2722              27 : char *MrSIDDataset::GetOGISDefn( GTIFDefn *psDefn )
    2723                 : {
    2724              27 :     OGRSpatialReference oSRS;
    2725                 : 
    2726              27 :     if( psDefn->Model != ModelTypeProjected 
    2727                 :         && psDefn->Model != ModelTypeGeographic )
    2728              12 :         return CPLStrdup("");
    2729                 :     
    2730                 : /* -------------------------------------------------------------------- */
    2731                 : /*      If this is a projected SRS we set the PROJCS keyword first      */
    2732                 : /*      to ensure that the GEOGCS will be a child.                      */
    2733                 : /* -------------------------------------------------------------------- */
    2734              15 :     if( psDefn->Model == ModelTypeProjected )
    2735                 :     {
    2736                 :         char    *pszPCSName;
    2737              13 :         int     bPCSNameSet = FALSE;
    2738                 : 
    2739              13 :         if( psDefn->PCS != KvUserDefined )
    2740                 :         {
    2741                 : 
    2742               5 :             if( GTIFGetPCSInfo( psDefn->PCS, &pszPCSName, NULL, NULL, NULL ) )
    2743               5 :                 bPCSNameSet = TRUE;
    2744                 :             
    2745               5 :             oSRS.SetNode( "PROJCS", bPCSNameSet ? pszPCSName : "unnamed" );
    2746               5 :             if( bPCSNameSet )
    2747               5 :                 GTIFFreeMemory( pszPCSName );
    2748                 : 
    2749               5 :             oSRS.SetAuthority( "PROJCS", "EPSG", psDefn->PCS );
    2750                 :         }
    2751                 :         else
    2752                 :         {
    2753                 :             char szPCSName[200];
    2754               8 :             strcpy( szPCSName, "unnamed" );
    2755               8 :             if ( GetMetadataElement( "GEOTIFF_NUM::1026::GTCitationGeoKey",
    2756                 :                                      szPCSName, sizeof(szPCSName) ) )
    2757               8 :                 oSRS.SetNode( "PROJCS", szPCSName );
    2758                 :         }
    2759                 :     }
    2760                 :     
    2761                 : /* ==================================================================== */
    2762                 : /*      Setup the GeogCS                                                */
    2763                 : /* ==================================================================== */
    2764              15 :     char        *pszGeogName = NULL;
    2765              15 :     char        *pszDatumName = NULL;
    2766              15 :     char        *pszPMName = NULL;
    2767              15 :     char        *pszSpheroidName = NULL;
    2768              15 :     char        *pszAngularUnits = NULL;
    2769                 :     double      dfInvFlattening, dfSemiMajor;
    2770                 :     char        szGCSName[200];
    2771                 :     
    2772              15 :     if( GetMetadataElement( "GEOTIFF_NUM::2049::GeogCitationGeoKey",
    2773                 :                             szGCSName, sizeof(szGCSName) ) )
    2774               1 :         pszGeogName = CPLStrdup(szGCSName);
    2775                 :     else
    2776                 :     {
    2777              14 :         GTIFGetGCSInfo( psDefn->GCS, &pszGeogName, NULL, NULL, NULL );
    2778              14 :         GTIFToCPLRecycleString(&pszGeogName);
    2779                 :     }
    2780              15 :     GTIFGetDatumInfo( psDefn->Datum, &pszDatumName, NULL );
    2781              15 :     GTIFToCPLRecycleString(&pszDatumName);
    2782              15 :     GTIFGetPMInfo( psDefn->PM, &pszPMName, NULL );
    2783              15 :     GTIFToCPLRecycleString(&pszPMName);
    2784              15 :     GTIFGetEllipsoidInfo( psDefn->Ellipsoid, &pszSpheroidName, NULL, NULL );
    2785              15 :     GTIFToCPLRecycleString(&pszSpheroidName);
    2786                 :     
    2787              15 :     GTIFGetUOMAngleInfo( psDefn->UOMAngle, &pszAngularUnits, NULL );
    2788              15 :     GTIFToCPLRecycleString(&pszAngularUnits);
    2789              15 :     if( pszAngularUnits == NULL )
    2790               0 :         pszAngularUnits = CPLStrdup("unknown");
    2791                 : 
    2792              15 :     if( pszDatumName != NULL )
    2793              15 :         WKTMassageDatum( &pszDatumName );
    2794                 : 
    2795              15 :     dfSemiMajor = psDefn->SemiMajor;
    2796              15 :     if( psDefn->SemiMajor == 0.0 )
    2797                 :     {
    2798               0 :         pszSpheroidName = CPLStrdup("unretrievable - using WGS84");
    2799               0 :         dfSemiMajor = SRS_WGS84_SEMIMAJOR;
    2800               0 :         dfInvFlattening = SRS_WGS84_INVFLATTENING;
    2801                 :     }
    2802              30 :     else if( (psDefn->SemiMinor / psDefn->SemiMajor) < 0.99999999999999999
    2803                 :              || (psDefn->SemiMinor / psDefn->SemiMajor) > 1.00000000000000001 )
    2804              15 :         dfInvFlattening = -1.0 / (psDefn->SemiMinor/psDefn->SemiMajor - 1.0);
    2805                 :     else
    2806               0 :         dfInvFlattening = 0.0; /* special flag for infinity */
    2807                 : 
    2808                 :     oSRS.SetGeogCS( pszGeogName, pszDatumName, 
    2809                 :                     pszSpheroidName, dfSemiMajor, dfInvFlattening,
    2810                 :                     pszPMName,
    2811                 :                     psDefn->PMLongToGreenwich / psDefn->UOMAngleInDegrees,
    2812                 :                     pszAngularUnits,
    2813              15 :                     psDefn->UOMAngleInDegrees * 0.0174532925199433 );
    2814                 : 
    2815              15 :     if( psDefn->GCS != KvUserDefined )
    2816              15 :         oSRS.SetAuthority( "GEOGCS", "EPSG", psDefn->GCS );
    2817                 : 
    2818              15 :     if( psDefn->Datum != KvUserDefined )
    2819              15 :         oSRS.SetAuthority( "DATUM", "EPSG", psDefn->Datum );
    2820                 : 
    2821              15 :     if( psDefn->Ellipsoid != KvUserDefined )
    2822              15 :         oSRS.SetAuthority( "SPHEROID", "EPSG", psDefn->Ellipsoid );
    2823                 : 
    2824              15 :     CPLFree( pszGeogName );
    2825              15 :     CPLFree( pszDatumName );
    2826              15 :     CPLFree( pszPMName );
    2827              15 :     CPLFree( pszSpheroidName );
    2828              15 :     CPLFree( pszAngularUnits );
    2829                 :         
    2830                 : /* ==================================================================== */
    2831                 : /*      Handle projection parameters.                                   */
    2832                 : /* ==================================================================== */
    2833              15 :     if( psDefn->Model == ModelTypeProjected )
    2834                 :     {
    2835                 : /* -------------------------------------------------------------------- */
    2836                 : /*      Make a local copy of parms, and convert back into the           */
    2837                 : /*      angular units of the GEOGCS and the linear units of the         */
    2838                 : /*      projection.                                                     */
    2839                 : /* -------------------------------------------------------------------- */
    2840                 :         double          adfParm[10];
    2841                 :         int             i;
    2842                 : 
    2843             104 :         for( i = 0; i < MIN(10,psDefn->nParms); i++ )
    2844              91 :             adfParm[i] = psDefn->ProjParm[i];
    2845                 : 
    2846              13 :         adfParm[0] /= psDefn->UOMAngleInDegrees;
    2847              13 :         adfParm[1] /= psDefn->UOMAngleInDegrees;
    2848              13 :         adfParm[2] /= psDefn->UOMAngleInDegrees;
    2849              13 :         adfParm[3] /= psDefn->UOMAngleInDegrees;
    2850                 :         
    2851              13 :         adfParm[5] /= psDefn->UOMLengthInMeters;
    2852              13 :         adfParm[6] /= psDefn->UOMLengthInMeters;
    2853                 :         
    2854                 : /* -------------------------------------------------------------------- */
    2855                 : /*      Translation the fundamental projection.                         */
    2856                 : /* -------------------------------------------------------------------- */
    2857              13 :         switch( psDefn->CTProjection )
    2858                 :         {
    2859                 :           case CT_TransverseMercator:
    2860                 :             oSRS.SetTM( adfParm[0], adfParm[1],
    2861                 :                         adfParm[4],
    2862               5 :                         adfParm[5], adfParm[6] );
    2863               5 :             break;
    2864                 : 
    2865                 :           case CT_TransvMercator_SouthOriented:
    2866                 :             oSRS.SetTMSO( adfParm[0], adfParm[1],
    2867                 :                           adfParm[4],
    2868               0 :                           adfParm[5], adfParm[6] );
    2869               0 :             break;
    2870                 : 
    2871                 :           case CT_Mercator:
    2872                 :             oSRS.SetMercator( adfParm[0], adfParm[1],
    2873                 :                               adfParm[4],
    2874               8 :                               adfParm[5], adfParm[6] );
    2875               8 :             break;
    2876                 : 
    2877                 :           case CT_ObliqueStereographic:
    2878                 :             oSRS.SetOS( adfParm[0], adfParm[1],
    2879                 :                         adfParm[4],
    2880               0 :                         adfParm[5], adfParm[6] );
    2881               0 :             break;
    2882                 : 
    2883                 :           case CT_Stereographic:
    2884                 :             oSRS.SetOS( adfParm[0], adfParm[1],
    2885                 :                         adfParm[4],
    2886               0 :                         adfParm[5], adfParm[6] );
    2887               0 :             break;
    2888                 : 
    2889                 :           case CT_ObliqueMercator: /* hotine */
    2890                 :             oSRS.SetHOM( adfParm[0], adfParm[1],
    2891                 :                          adfParm[2], adfParm[3],
    2892                 :                          adfParm[4],
    2893               0 :                          adfParm[5], adfParm[6] );
    2894               0 :             break;
    2895                 :         
    2896                 :           case CT_EquidistantConic: 
    2897                 :             oSRS.SetEC( adfParm[0], adfParm[1],
    2898                 :                         adfParm[2], adfParm[3],
    2899               0 :                         adfParm[5], adfParm[6] );
    2900               0 :             break;
    2901                 :         
    2902                 :           case CT_CassiniSoldner:
    2903                 :             oSRS.SetCS( adfParm[0], adfParm[1],
    2904               0 :                         adfParm[5], adfParm[6] );
    2905               0 :             break;
    2906                 :         
    2907                 :           case CT_Polyconic:
    2908                 :             oSRS.SetPolyconic( adfParm[0], adfParm[1],
    2909               0 :                                adfParm[5], adfParm[6] );
    2910               0 :             break;
    2911                 : 
    2912                 :           case CT_AzimuthalEquidistant:
    2913                 :             oSRS.SetAE( adfParm[0], adfParm[1],
    2914               0 :                         adfParm[5], adfParm[6] );
    2915               0 :             break;
    2916                 :         
    2917                 :           case CT_MillerCylindrical:
    2918                 :             oSRS.SetMC( adfParm[0], adfParm[1],
    2919               0 :                         adfParm[5], adfParm[6] );
    2920               0 :             break;
    2921                 :         
    2922                 :           case CT_Equirectangular:
    2923                 :             oSRS.SetEquirectangular( adfParm[0], adfParm[1],
    2924               0 :                                      adfParm[5], adfParm[6] );
    2925               0 :             break;
    2926                 :         
    2927                 :           case CT_Gnomonic:
    2928                 :             oSRS.SetGnomonic( adfParm[0], adfParm[1],
    2929               0 :                               adfParm[5], adfParm[6] );
    2930               0 :             break;
    2931                 :         
    2932                 :           case CT_LambertAzimEqualArea:
    2933                 :             oSRS.SetLAEA( adfParm[0], adfParm[1],
    2934               0 :                           adfParm[5], adfParm[6] );
    2935               0 :             break;
    2936                 :         
    2937                 :           case CT_Orthographic:
    2938                 :             oSRS.SetOrthographic( adfParm[0], adfParm[1],
    2939               0 :                                   adfParm[5], adfParm[6] );
    2940               0 :             break;
    2941                 :         
    2942                 :           case CT_Robinson:
    2943                 :             oSRS.SetRobinson( adfParm[1],
    2944               0 :                               adfParm[5], adfParm[6] );
    2945               0 :             break;
    2946                 :         
    2947                 :           case CT_Sinusoidal:
    2948                 :             oSRS.SetSinusoidal( adfParm[1],
    2949               0 :                                 adfParm[5], adfParm[6] );
    2950               0 :             break;
    2951                 :         
    2952                 :           case CT_VanDerGrinten:
    2953                 :             oSRS.SetVDG( adfParm[1],
    2954               0 :                          adfParm[5], adfParm[6] );
    2955               0 :             break;
    2956                 : 
    2957                 :           case CT_PolarStereographic:
    2958                 :             oSRS.SetPS( adfParm[0], adfParm[1],
    2959                 :                         adfParm[4],
    2960               0 :                         adfParm[5], adfParm[6] );
    2961               0 :             break;
    2962                 :         
    2963                 :           case CT_LambertConfConic_2SP:
    2964                 :             oSRS.SetLCC( adfParm[2], adfParm[3],
    2965                 :                          adfParm[0], adfParm[1],
    2966               0 :                          adfParm[5], adfParm[6] );
    2967               0 :             break;
    2968                 : 
    2969                 :           case CT_LambertConfConic_1SP:
    2970                 :             oSRS.SetLCC1SP( adfParm[0], adfParm[1],
    2971                 :                             adfParm[4],
    2972               0 :                             adfParm[5], adfParm[6] );
    2973               0 :             break;
    2974                 :         
    2975                 :           case CT_AlbersEqualArea:
    2976                 :             oSRS.SetACEA( adfParm[0], adfParm[1],
    2977                 :                           adfParm[2], adfParm[3],
    2978               0 :                           adfParm[5], adfParm[6] );
    2979               0 :             break;
    2980                 : 
    2981                 :           case CT_NewZealandMapGrid:
    2982                 :             oSRS.SetNZMG( adfParm[0], adfParm[1],
    2983               0 :                           adfParm[5], adfParm[6] );
    2984                 :             break;
    2985                 :         }
    2986                 : 
    2987                 : /* -------------------------------------------------------------------- */
    2988                 : /*      Set projection units.                                           */
    2989                 : /* -------------------------------------------------------------------- */
    2990              13 :         char    *pszUnitsName = NULL;
    2991                 :         
    2992              13 :         GTIFGetUOMLengthInfo( psDefn->UOMLength, &pszUnitsName, NULL );
    2993                 : 
    2994              26 :         if( pszUnitsName != NULL && psDefn->UOMLength != KvUserDefined )
    2995                 :         {
    2996              13 :             oSRS.SetLinearUnits( pszUnitsName, psDefn->UOMLengthInMeters );
    2997              13 :             oSRS.SetAuthority( "PROJCS|UNIT", "EPSG", psDefn->UOMLength );
    2998                 :         }
    2999                 :         else
    3000               0 :             oSRS.SetLinearUnits( "unknown", psDefn->UOMLengthInMeters );
    3001                 : 
    3002              13 :         GTIFFreeMemory( pszUnitsName );
    3003                 :     }
    3004                 :     
    3005                 : /* -------------------------------------------------------------------- */
    3006                 : /*      Return the WKT serialization of the object.                     */
    3007                 : /* -------------------------------------------------------------------- */
    3008                 :     char        *pszWKT;
    3009                 : 
    3010              15 :     oSRS.FixupOrdering();
    3011                 : 
    3012              15 :     if( oSRS.exportToWkt( &pszWKT ) == OGRERR_NONE )
    3013              15 :         return pszWKT;
    3014                 :     else
    3015               0 :         return NULL;
    3016                 : }
    3017                 : 
    3018                 : #ifdef MRSID_ESDK
    3019                 : 
    3020                 : /************************************************************************/
    3021                 : /* ==================================================================== */
    3022                 : /*                        MrSIDDummyImageReader                         */
    3023                 : /*                                                                      */
    3024                 : /*  This is a helper class to wrap GDAL calls in MrSID interface.       */
    3025                 : /* ==================================================================== */
    3026                 : /************************************************************************/
    3027                 : 
    3028                 : class MrSIDDummyImageReader : public LTIImageReader
    3029                 : {
    3030                 :   public:
    3031                 : 
    3032                 :     MrSIDDummyImageReader( GDALDataset *poSrcDS );
    3033                 :     ~MrSIDDummyImageReader();
    3034                 :     LT_STATUS           initialize();
    3035                 :     lt_int64            getPhysicalFileSize(void) const { return 0; };
    3036                 : 
    3037                 :   private:
    3038                 :     GDALDataset         *poDS;
    3039                 :     GDALDataType        eDataType;
    3040                 :     LTIDataType         eSampleType;
    3041                 :     const LTIPixel      *poPixel;
    3042                 :     
    3043                 :     double              adfGeoTransform[6];
    3044                 : 
    3045                 :     virtual LT_STATUS   decodeStrip( LTISceneBuffer& stripBuffer,
    3046                 :                                      const LTIScene& stripScene );
    3047                 :     virtual LT_STATUS   decodeBegin( const LTIScene& )
    3048                 :                             { return LT_STS_Success; };
    3049                 :     virtual LT_STATUS   decodeEnd() { return LT_STS_Success; };
    3050                 : };
    3051                 : 
    3052                 : /************************************************************************/
    3053                 : /*                        MrSIDDummyImageReader()                       */
    3054                 : /************************************************************************/
    3055                 : 
    3056                 : MrSIDDummyImageReader::MrSIDDummyImageReader( GDALDataset *poSrcDS ) :
    3057                 :                                             LTIImageReader(), poDS(poSrcDS)
    3058                 : {
    3059                 :     poPixel = NULL;
    3060                 : }
    3061                 : 
    3062                 : /************************************************************************/
    3063                 : /*                        ~MrSIDDummyImageReader()                      */
    3064                 : /************************************************************************/
    3065                 : 
    3066                 : MrSIDDummyImageReader::~MrSIDDummyImageReader()
    3067                 : {
    3068                 :     if ( poPixel )
    3069                 :         delete poPixel;
    3070                 : }
    3071                 : 
    3072                 : /************************************************************************/
    3073                 : /*                             initialize()                             */
    3074                 : /************************************************************************/
    3075                 : 
    3076                 : LT_STATUS MrSIDDummyImageReader::initialize()
    3077                 : {
    3078                 :     LT_STATUS eStat = LT_STS_Uninit;
    3079                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
    3080                 :     if ( !LT_SUCCESS(eStat = LTIImageReader::init()) )
    3081                 :         return eStat;
    3082                 : #else
    3083                 :     if ( !LT_SUCCESS(eStat = LTIImageReader::initialize()) )
    3084                 :         return eStat;
    3085                 : #endif
    3086                 :     
    3087                 :     lt_uint16 nBands = (lt_uint16)poDS->GetRasterCount();
    3088                 :     LTIColorSpace eColorSpace = LTI_COLORSPACE_RGB;
    3089                 :     switch ( nBands )
    3090                 :     {
    3091                 :         case 1:
    3092                 :             eColorSpace = LTI_COLORSPACE_GRAYSCALE;
    3093                 :             break;
    3094                 :         case 3:
    3095                 :             eColorSpace = LTI_COLORSPACE_RGB;
    3096                 :             break;
    3097                 :         default:
    3098                 :             eColorSpace = LTI_COLORSPACE_MULTISPECTRAL;
    3099                 :             break;
    3100                 :     }
    3101                 :     
    3102                 :     eDataType = poDS->GetRasterBand(1)->GetRasterDataType();
    3103                 :     switch ( eDataType )
    3104                 :     {
    3105                 :         case GDT_UInt16:
    3106                 :             eSampleType = LTI_DATATYPE_UINT16;
    3107                 :             break;
    3108                 :         case GDT_Int16:
    3109                 :             eSampleType = LTI_DATATYPE_SINT16;
    3110                 :             break;
    3111                 :         case GDT_UInt32:
    3112                 :             eSampleType = LTI_DATATYPE_UINT32;
    3113                 :             break;
    3114                 :         case GDT_Int32:
    3115                 :             eSampleType = LTI_DATATYPE_SINT32;
    3116                 :             break;
    3117                 :         case GDT_Float32:
    3118                 :             eSampleType = LTI_DATATYPE_FLOAT32;
    3119                 :             break;
    3120                 :         case GDT_Float64:
    3121                 :             eSampleType = LTI_DATATYPE_FLOAT64;
    3122                 :             break;
    3123                 :         case GDT_Byte:
    3124                 :         default:
    3125                 :             eSampleType = LTI_DATATYPE_UINT8;
    3126                 :             break;
    3127                 :     }
    3128                 : 
    3129                 :     poPixel = new LTIDLLPixel<LTIPixel>( eColorSpace, nBands, eSampleType );
    3130                 :     if ( !LT_SUCCESS(setPixelProps(*poPixel)) )
    3131                 :         return LT_STS_Failure;
    3132                 : 
    3133                 :     if ( !LT_SUCCESS(setDimensions(poDS->GetRasterXSize(),
    3134                 :                                    poDS->GetRasterYSize())) )
    3135                 :         return LT_STS_Failure;
    3136                 : 
    3137                 :     if ( poDS->GetGeoTransform( adfGeoTransform ) == CE_None )
    3138                 :     {
    3139                 : #ifdef MRSID_SDK_40
    3140                 :         LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
    3141                 :                           adfGeoTransform[3] + adfGeoTransform[5] / 2,
    3142                 :                           adfGeoTransform[1], adfGeoTransform[5],
    3143                 :                           adfGeoTransform[2], adfGeoTransform[4], NULL,
    3144                 :                           poDS->GetProjectionRef() );
    3145                 : #else
    3146                 :         LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
    3147                 :                           adfGeoTransform[3] + adfGeoTransform[5] / 2,
    3148                 :                           adfGeoTransform[1], adfGeoTransform[5],
    3149                 :                           adfGeoTransform[2], adfGeoTransform[4], 
    3150                 :                           poDS->GetProjectionRef() );
    3151                 : #endif
    3152                 :         if ( !LT_SUCCESS(setGeoCoord( oGeo )) )
    3153                 :             return LT_STS_Failure;
    3154                 :     }
    3155                 : 
    3156                 :     /*int     bSuccess;
    3157                 :     double  dfNoDataValue = poDS->GetNoDataValue( &bSuccess );
    3158                 :     if ( bSuccess )
    3159                 :     {
    3160                 :         LTIPixel    oNoDataPixel( *poPixel );
    3161                 :         lt_uint16   iBand;
    3162                 : 
    3163                 :         for (iBand = 0; iBand < (lt_uint16)poDS->GetRasterCount(); iBand++)
    3164                 :             oNoDataPixel.setSampleValueFloat32( iBand, dfNoDataValue );
    3165                 :         if ( !LT_SUCCESS(setNoDataPixel( &oNoDataPixel )) )
    3166                 :             return LT_STS_Failure;
    3167                 :     }*/
    3168                 : 
    3169                 :     setDefaultDynamicRange();
    3170                 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3171                 :     setClassicalMetadata();
    3172                 : #endif
    3173                 : 
    3174                 :     return LT_STS_Success;
    3175                 : }
    3176                 : 
    3177                 : /************************************************************************/
    3178                 : /*                             decodeStrip()                            */
    3179                 : /************************************************************************/
    3180                 : 
    3181                 : LT_STATUS MrSIDDummyImageReader::decodeStrip(LTISceneBuffer& stripData,
    3182                 :                                              const LTIScene& stripScene)
    3183                 : 
    3184                 : {
    3185                 :     const lt_int32  nXOff = stripScene.getUpperLeftCol();
    3186                 :     const lt_int32  nYOff = stripScene.getUpperLeftRow();
    3187                 :     const lt_int32  nBufXSize = stripScene.getNumCols();
    3188                 :     const lt_int32  nBufYSize = stripScene.getNumRows();
    3189                 :     const lt_int32  nDataBufXSize = stripData.getTotalNumCols();
    3190                 :     const lt_int32  nDataBufYSize = stripData.getTotalNumRows();
    3191                 :     const lt_uint16 nBands = poPixel->getNumBands();
    3192                 : 
    3193                 :     void *pData = CPLMalloc(nDataBufXSize * nDataBufYSize * poPixel->getNumBytes());
    3194                 :     if ( !pData )
    3195                 :     {
    3196                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3197                 :                   "MrSIDDummyImageReader::decodeStrip(): "
    3198                 :                   "Cannot allocate enough space for scene buffer" );
    3199                 :         return LT_STS_Failure;
    3200                 :     }
    3201                 : 
    3202                 :     poDS->RasterIO( GF_Read, nXOff, nYOff, nBufXSize, nBufYSize, 
    3203                 :                     pData, nBufXSize, nBufYSize, eDataType, nBands, NULL, 
    3204                 :                     0, 0, 0 );
    3205                 : 
    3206                 :     stripData.importDataBSQ( pData );
    3207                 :     CPLFree( pData );
    3208                 :     return LT_STS_Success;
    3209                 : }
    3210                 : 
    3211                 : /************************************************************************/
    3212                 : /*                             FlushCache()                             */
    3213                 : /************************************************************************/
    3214                 : 
    3215                 : void MrSIDDataset::FlushCache()
    3216                 : 
    3217                 : {
    3218                 :     GDALDataset::FlushCache();
    3219                 : }
    3220                 : 
    3221                 : /************************************************************************/
    3222                 : /*                          MrSIDCreateCopy()                           */
    3223                 : /************************************************************************/
    3224                 : 
    3225                 : static GDALDataset *
    3226                 : MrSIDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
    3227                 :                  int bStrict, char ** papszOptions, 
    3228                 :                  GDALProgressFunc pfnProgress, void * pProgressData )
    3229                 : 
    3230                 : { 
    3231                 :     const char* pszVersion = CSLFetchNameValue(papszOptions, "VERSION");
    3232                 : #ifdef MRSID_HAVE_MG4WRITE
    3233                 :     int iVersion = pszVersion ? atoi(pszVersion) : 4;
    3234                 : #else
    3235                 :     int iVersion = pszVersion ? atoi(pszVersion) : 3;
    3236                 : #endif
    3237                 :     LT_STATUS eStat = LT_STS_Uninit;
    3238                 : 
    3239                 : #ifdef DEBUG
    3240                 :     bool bMeter = false;
    3241                 : #else
    3242                 :     bool bMeter = true;
    3243                 : #endif    
    3244                 :     
    3245                 :     if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
    3246                 :     {
    3247                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
    3248                 :                   "MrSID driver ignores color table. "
    3249                 :                   "The source raster band will be considered as grey level.\n"
    3250                 :                   "Consider using color table expansion (-expand option in gdal_translate)\n");
    3251                 :         if (bStrict)
    3252                 :             return NULL;
    3253                 :     }
    3254                 : 
    3255                 :     MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
    3256                 :     if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
    3257                 :     {
    3258                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3259                 :                   "MrSIDProgress.setProgressStatus failed.\n%s",
    3260                 :                   getLastStatusString( eStat ) );
    3261                 :         return NULL;
    3262                 :     }
    3263                 : 
    3264                 :     // Create the file.                                               
    3265                 :     MrSIDDummyImageReader oImageReader( poSrcDS );
    3266                 :     if( LT_FAILURE( eStat = oImageReader.initialize() ) )
    3267                 :     {
    3268                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3269                 :                   "MrSIDDummyImageReader.Initialize failed.\n%s",
    3270                 :                   getLastStatusString( eStat ) );
    3271                 :         return NULL;
    3272                 :     }
    3273                 : 
    3274                 :     LTIGeoFileImageWriter *poImageWriter = NULL;
    3275                 :     switch (iVersion)
    3276                 :     {
    3277                 :     case 2: {
    3278                 :         // Output Mrsid Version 2 file.
    3279                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3280                 :         LTIDLLDefault<MG2ImageWriter> *poMG2ImageWriter;
    3281                 :         poMG2ImageWriter = new LTIDLLDefault<MG2ImageWriter>;
    3282                 :         eStat = poMG2ImageWriter->initialize(&oImageReader);
    3283                 : #else
    3284                 :         LTIDLLWriter<MG2ImageWriter> *poMG2ImageWriter;
    3285                 :         poMG2ImageWriter = new LTIDLLWriter<MG2ImageWriter>(&oImageReader);
    3286                 :         eStat = poMG2ImageWriter->initialize();
    3287                 : #endif
    3288                 :         if( LT_FAILURE( eStat ) )
    3289                 :         {
    3290                 :             delete poMG2ImageWriter;
    3291                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3292                 :                       "MG2ImageWriter.initialize() failed.\n%s",
    3293                 :                       getLastStatusString( eStat ) );
    3294                 :             return NULL;
    3295                 :         }
    3296                 : 
    3297                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3298                 :         eStat = poMG2ImageWriter->setEncodingApplication("MrSID Driver",
    3299                 :                                                          GDALVersionInfo("--version"));
    3300                 :         if( LT_FAILURE( eStat ) )
    3301                 :         {
    3302                 :             delete poMG2ImageWriter;
    3303                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3304                 :                       "MG2ImageWriter.setEncodingApplication() failed.\n%s",
    3305                 :                       getLastStatusString( eStat ) );
    3306                 :             return NULL;
    3307                 :         }
    3308                 : #endif
    3309                 : 
    3310                 :         poMG2ImageWriter->setUsageMeterEnabled(bMeter);
    3311                 : 
    3312                 :         poMG2ImageWriter->params().setBlockSize(poMG2ImageWriter->params().getBlockSize());
    3313                 : 
    3314                 :         // check for compression option
    3315                 :         const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
    3316                 :         if( pszValue != NULL )
    3317                 :             poMG2ImageWriter->params().setCompressionRatio( (float)atof(pszValue) );
    3318                 : 
    3319                 :         poImageWriter = poMG2ImageWriter;
    3320                 : 
    3321                 :         break; }
    3322                 :     case 3: {
    3323                 :         // Output Mrsid Version 3 file.
    3324                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3325                 :         LTIDLLDefault<MG3ImageWriter> *poMG3ImageWriter;
    3326                 :         poMG3ImageWriter = new LTIDLLDefault<MG3ImageWriter>;
    3327                 :         eStat = poMG3ImageWriter->initialize(&oImageReader);
    3328                 : #else
    3329                 :         LTIDLLWriter<MG3ImageWriter> *poMG3ImageWriter;
    3330                 :         poMG3ImageWriter = new LTIDLLWriter<MG3ImageWriter>(&oImageReader);
    3331                 :         eStat = poMG3ImageWriter->initialize();
    3332                 : #endif
    3333                 :         if( LT_FAILURE( eStat ) )
    3334                 :         {
    3335                 :             delete poMG3ImageWriter;
    3336                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3337                 :                       "MG3ImageWriter.initialize() failed.\n%s",
    3338                 :                       getLastStatusString( eStat ) );
    3339                 :             return NULL;
    3340                 :         }
    3341                 : 
    3342                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3343                 :         eStat = poMG3ImageWriter->setEncodingApplication("MrSID Driver",
    3344                 :                                                          GDALVersionInfo("--version"));
    3345                 :         if( LT_FAILURE( eStat ) )
    3346                 :         {
    3347                 :             delete poMG3ImageWriter;
    3348                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3349                 :                       "MG3ImageWriter.setEncodingApplication() failed.\n%s",
    3350                 :                       getLastStatusString( eStat ) );
    3351                 :             return NULL;
    3352                 :         }
    3353                 : #endif
    3354                 : 
    3355                 :         // usage meter should only be disabled for debugging
    3356                 :         poMG3ImageWriter->setUsageMeterEnabled(bMeter);
    3357                 : 
    3358                 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3359                 :         // Set 64-bit Interface for large files.
    3360                 :         poMG3ImageWriter->setFileStream64(true);
    3361                 : #endif
    3362                 : 
    3363                 :         // set 2 pass optimizer option
    3364                 :         if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
    3365                 :             poMG3ImageWriter->params().setTwoPassOptimizer( true );
    3366                 : 
    3367                 :         // set filesize in KB
    3368                 :         const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
    3369                 :         if( pszValue != NULL )
    3370                 :             poMG3ImageWriter->params().setTargetFilesize( atoi(pszValue) );
    3371                 : 
    3372                 :         poImageWriter = poMG3ImageWriter;
    3373                 : 
    3374                 :         break; }
    3375                 : #ifdef MRSID_HAVE_MG4WRITE
    3376                 :     case 4: {
    3377                 :         // Output Mrsid Version 4 file.
    3378                 :         LTIDLLDefault<MG4ImageWriter> *poMG4ImageWriter;
    3379                 :         poMG4ImageWriter = new LTIDLLDefault<MG4ImageWriter>;
    3380                 :         eStat = poMG4ImageWriter->initialize(&oImageReader, NULL, NULL);
    3381                 :         if( LT_FAILURE( eStat ) )
    3382                 :         {
    3383                 :             delete poMG4ImageWriter;
    3384                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3385                 :                       "MG3ImageWriter.initialize() failed.\n%s",
    3386                 :                       getLastStatusString( eStat ) );
    3387                 :             return NULL;
    3388                 :         }
    3389                 : 
    3390                 :         eStat = poMG4ImageWriter->setEncodingApplication("MrSID Driver",
    3391                 :                                                          GDALVersionInfo("--version"));
    3392                 :         if( LT_FAILURE( eStat ) )
    3393                 :         {
    3394                 :             delete poMG4ImageWriter;
    3395                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3396                 :                       "MG3ImageWriter.setEncodingApplication() failed.\n%s",
    3397                 :                       getLastStatusString( eStat ) );
    3398                 :             return NULL;
    3399                 :         }
    3400                 : 
    3401                 :         // usage meter should only be disabled for debugging
    3402                 :         poMG4ImageWriter->setUsageMeterEnabled(bMeter);
    3403                 : 
    3404                 :         // set 2 pass optimizer option
    3405                 :         if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
    3406                 :             poMG4ImageWriter->params().setTwoPassOptimizer( true );
    3407                 : 
    3408                 :         // set filesize in KB
    3409                 :         const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
    3410                 :         if( pszValue != NULL )
    3411                 :             poMG4ImageWriter->params().setTargetFilesize( atoi(pszValue) );
    3412                 : 
    3413                 :         poImageWriter = poMG4ImageWriter;
    3414                 : 
    3415                 :         break; }
    3416                 : #endif /* MRSID_HAVE_MG4WRITE */
    3417                 :     default:
    3418                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3419                 :                   "Invalid MrSID generation specified (VERSION=%s).",
    3420                 :                   pszVersion );
    3421                 :         return NULL;
    3422                 :     }
    3423                 : 
    3424                 :     // set output filename
    3425                 :     poImageWriter->setOutputFileSpec( pszFilename );
    3426                 : 
    3427                 :     // set progress delegate
    3428                 :     poImageWriter->setProgressDelegate(&oProgressDelegate);
    3429                 : 
    3430                 :     // set defaults
    3431                 :     poImageWriter->setStripHeight(poImageWriter->getStripHeight());
    3432                 : 
    3433                 :     // set MrSID world file
    3434                 :     if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
    3435                 :         poImageWriter->setWorldFileSupport( true );
    3436                 : 
    3437                 :     // write the scene
    3438                 :     int nXSize = poSrcDS->GetRasterXSize();
    3439                 :     int nYSize = poSrcDS->GetRasterYSize();
    3440                 :     const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
    3441                 :     if( LT_FAILURE( eStat = poImageWriter->write( oScene ) ) )
    3442                 :     {
    3443                 :         delete poImageWriter;
    3444                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3445                 :                   "MG2ImageWriter.write() failed.\n%s",
    3446                 :                   getLastStatusString( eStat ) );
    3447                 :         return NULL;
    3448                 :     }
    3449                 : 
    3450                 :     delete poImageWriter;
    3451                 : /* -------------------------------------------------------------------- */
    3452                 : /*      Re-open dataset, and copy any auxilary pam information.         */
    3453                 : /* -------------------------------------------------------------------- */
    3454                 :     GDALPamDataset *poDS = (GDALPamDataset *) 
    3455                 :         GDALOpen( pszFilename, GA_ReadOnly );
    3456                 : 
    3457                 :     if( poDS )
    3458                 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    3459                 : 
    3460                 :     return poDS;
    3461                 : }
    3462                 : 
    3463                 : #ifdef MRSID_J2K
    3464                 : /************************************************************************/
    3465                 : /*                           JP2CreateCopy()                            */
    3466                 : /************************************************************************/
    3467                 : 
    3468                 : static GDALDataset *
    3469                 : JP2CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
    3470                 :                  int bStrict, char ** papszOptions, 
    3471                 :                  GDALProgressFunc pfnProgress, void * pProgressData )
    3472                 : 
    3473                 : { 
    3474                 : #ifdef DEBUG
    3475                 :     bool bMeter = false;
    3476                 : #else
    3477                 :     bool bMeter = true;
    3478                 : #endif    
    3479                 : 
    3480                 :     int nXSize = poSrcDS->GetRasterXSize();
    3481                 :     int nYSize = poSrcDS->GetRasterYSize();
    3482                 :     LT_STATUS  eStat;
    3483                 :     
    3484                 :     if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
    3485                 :     {
    3486                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
    3487                 :                   "MrSID driver ignores color table. "
    3488                 :                   "The source raster band will be considered as grey level.\n"
    3489                 :                   "Consider using color table expansion (-expand option in gdal_translate)\n");
    3490                 :         if (bStrict)
    3491                 :             return NULL;
    3492                 :     }
    3493                 : 
    3494                 :     MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
    3495                 :     if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
    3496                 :     {
    3497                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3498                 :                   "MrSIDProgress.setProgressStatus failed.\n%s",
    3499                 :                   getLastStatusString( eStat ) );
    3500                 :         return NULL;
    3501                 :     }
    3502                 : 
    3503                 :     // Create the file.   
    3504                 :     MrSIDDummyImageReader oImageReader( poSrcDS );
    3505                 :     eStat = oImageReader.initialize();
    3506                 :     if( eStat != LT_STS_Success )
    3507                 :     {
    3508                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3509                 :                   "MrSIDDummyImageReader.Initialize failed.\n%s",
    3510                 :                   getLastStatusString( eStat ) );
    3511                 :         return NULL;
    3512                 :     }
    3513                 :       
    3514                 : #if !defined(MRSID_POST5)
    3515                 :     J2KImageWriter oImageWriter(&oImageReader);
    3516                 :     eStat = oImageWriter.initialize();
    3517                 : #elif !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3518                 :     JP2WriterManager oImageWriter(&oImageReader);
    3519                 :     eStat = oImageWriter.initialize();
    3520                 : #else
    3521                 :     JP2WriterManager oImageWriter;
    3522                 :     eStat = oImageWriter.initialize(&oImageReader);
    3523                 : #endif
    3524                 :     if( eStat != LT_STS_Success )
    3525                 :     {
    3526                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3527                 :                   "J2KImageWriter.Initialize failed.\n%s",
    3528                 :                   getLastStatusString( eStat ) );
    3529                 :         return NULL;
    3530                 :     }
    3531                 : 
    3532                 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3533                 :     // Set 64-bit Interface for large files.
    3534                 :     oImageWriter.setFileStream64(true);
    3535                 : #endif
    3536                 : 
    3537                 :     oImageWriter.setUsageMeterEnabled(bMeter);
    3538                 :       
    3539                 :     // set output filename
    3540                 :     oImageWriter.setOutputFileSpec( pszFilename );
    3541                 : 
    3542                 :     // set progress delegate
    3543                 :     oImageWriter.setProgressDelegate(&oProgressDelegate);
    3544                 : 
    3545                 :     // Set defaults
    3546                 :     //oImageWriter.setStripHeight(oImageWriter.getStripHeight());
    3547                 : 
    3548                 :     // set MrSID world file
    3549                 :     if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
    3550                 :         oImageWriter.setWorldFileSupport( true );
    3551                 :       
    3552                 :     // check for compression option
    3553                 :     const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
    3554                 :     if( pszValue != NULL )
    3555                 :         oImageWriter.params().setCompressionRatio( (float)atof(pszValue) );
    3556                 :         
    3557                 :     pszValue = CSLFetchNameValue(papszOptions, "XMLPROFILE");
    3558                 :     if( pszValue != NULL )
    3559                 :     {
    3560                 :         LTFileSpec xmlprofile(pszValue);
    3561                 :         eStat = oImageWriter.params().readProfile(xmlprofile);
    3562                 :         if( eStat != LT_STS_Success )
    3563                 :         {
    3564                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3565                 :                       "JPCWriterParams.readProfile failed.\n%s",
    3566                 :                       getLastStatusString( eStat ) );
    3567                 :             return NULL;
    3568                 :         }
    3569                 :     }
    3570                 : 
    3571                 :     // write the scene
    3572                 :     const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
    3573                 :     eStat = oImageWriter.write( oScene );
    3574                 :     if( eStat != LT_STS_Success )
    3575                 :     {
    3576                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3577                 :                   "J2KImageWriter.write() failed.\n%s",
    3578                 :                   getLastStatusString( eStat ) );
    3579                 :         return NULL;
    3580                 :     }
    3581                 :   
    3582                 : /* -------------------------------------------------------------------- */
    3583                 : /*      Re-open dataset, and copy any auxilary pam information.         */
    3584                 : /* -------------------------------------------------------------------- */
    3585                 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
    3586                 :     GDALPamDataset *poDS = (GDALPamDataset*) JP2Open(&oOpenInfo);
    3587                 : 
    3588                 :     if( poDS )  
    3589                 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    3590                 : 
    3591                 :     return poDS;
    3592                 : }
    3593                 : #endif /* MRSID_J2K */
    3594                 : #endif /* MRSID_ESDK */
    3595                 : 
    3596                 : /************************************************************************/
    3597                 : /*                        GDALRegister_MrSID()                          */
    3598                 : /************************************************************************/
    3599                 : 
    3600             582 : void GDALRegister_MrSID()
    3601                 : 
    3602                 : {
    3603                 :     GDALDriver  *poDriver;
    3604                 :     
    3605             582 :     if (! GDAL_CHECK_VERSION("MrSID driver"))
    3606               0 :         return;
    3607                 : 
    3608                 : /* -------------------------------------------------------------------- */
    3609                 : /*      MrSID driver.                                                   */
    3610                 : /* -------------------------------------------------------------------- */
    3611             582 :     if( GDALGetDriverByName( "MrSID" ) == NULL )
    3612                 :     {
    3613             561 :         poDriver = new GDALDriver();
    3614                 : 
    3615             561 :         poDriver->SetDescription( "MrSID" );
    3616                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    3617             561 :                         "Multi-resolution Seamless Image Database (MrSID)" );
    3618             561 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_mrsid.html" );
    3619             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "sid" );
    3620                 : 
    3621                 : #ifdef MRSID_ESDK
    3622                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    3623                 :                                    "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
    3624                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    3625                 : "<CreationOptionList>"
    3626                 : // Version 2 Options
    3627                 : "   <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
    3628                 : // Version 3 Options
    3629                 : "   <Option name='TWOPASS' type='int' description='Use twopass optimizer algorithm'/>"
    3630                 : "   <Option name='FILESIZE' type='int' description='Set target file size (0 implies lossless compression)'/>"
    3631                 : // Version 2 and 3 Option
    3632                 : "   <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
    3633                 : // Version Type
    3634                 : "   <Option name='VERSION' type='int' description='Valid versions are 2 and 3, default = 3'/>"
    3635                 : "</CreationOptionList>" );
    3636                 : 
    3637                 :         poDriver->pfnCreateCopy = MrSIDCreateCopy;
    3638                 : 
    3639                 : #else
    3640                 :         /* In read-only mode, we support VirtualIO. I don't think this is the case */
    3641                 :         /* for MrSIDCreateCopy() */
    3642             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    3643                 : #endif
    3644             561 :         poDriver->pfnIdentify = MrSIDIdentify;
    3645             561 :         poDriver->pfnOpen = MrSIDOpen;
    3646                 : 
    3647             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    3648                 :     }
    3649                 : 
    3650                 : /* -------------------------------------------------------------------- */
    3651                 : /*      JP2MRSID driver.                                                */
    3652                 : /* -------------------------------------------------------------------- */
    3653                 : #ifdef MRSID_J2K
    3654             582 :     if( GDALGetDriverByName( "JP2MrSID" ) == NULL )
    3655                 :     {
    3656             561 :         poDriver = new GDALDriver();
    3657                 : 
    3658             561 :         poDriver->SetDescription( "JP2MrSID" );
    3659                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    3660             561 :                         "MrSID JPEG2000" );
    3661             561 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_jp2mrsid.html" );
    3662             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
    3663                 : 
    3664                 : #ifdef MRSID_ESDK
    3665                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    3666                 :                                    "Byte Int16 UInt16" );
    3667                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    3668                 : "<CreationOptionList>"
    3669                 : "   <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
    3670                 : "   <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
    3671                 : "   <Option name='XMLPROFILE' type='string' description='Use named xml profile file'/>"
    3672                 : "</CreationOptionList>" );
    3673                 : 
    3674                 :         poDriver->pfnCreateCopy = JP2CreateCopy;
    3675                 : #else
    3676                 :         /* In read-only mode, we support VirtualIO. I don't think this is the case */
    3677                 :         /* for JP2CreateCopy() */
    3678             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    3679                 : #endif
    3680             561 :         poDriver->pfnIdentify = JP2Identify;
    3681             561 :         poDriver->pfnOpen = JP2Open;
    3682                 : 
    3683             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    3684                 :     }
    3685                 : #endif /* def MRSID_J2K */
    3686                 : }
    3687                 : 
    3688                 : #if defined(MRSID_USE_TIFFSYMS_WORKAROUND)
    3689                 : extern "C" {
    3690                 : 
    3691                 : /* This is not pretty but I am not sure how else to get the plugin to build
    3692                 :  * against the ESDK.  ESDK symbol dependencies bring in __TIFFmemcpy and
    3693                 :  * __gtiff_size, which are not exported from gdal.dll.  Rather than link these
    3694                 :  * symbols from the ESDK distribution of GDAL, or link in the entire gdal.lib
    3695                 :  * statically, it seemed safer and smaller to bring in just the objects that
    3696                 :  * wouldsatisfy these symbols from the enclosing GDAL build.  However, doing
    3697                 :  * so pulls in a few more dependencies.  /Gy and /OPT:REF did not seem to help
    3698                 :  * things, so I have implemented no-op versions of these symbols since they
    3699                 :  * do not actually get called.  If the MrSID ESDK ever comes to require the
    3700                 :  * actual versions of these functions, we'll hope duplicate symbol errors will
    3701                 :  * bring attention back to this problem.
    3702                 :  */
    3703                 : void TIFFClientOpen() {}
    3704                 : void TIFFError() {}
    3705                 : void TIFFGetField() {}
    3706                 : void TIFFSetField() {}
    3707                 : 
    3708                 : }
    3709                 : #endif
    3710                 : 

Generated by: LCOV version 1.7