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

       1                 : /******************************************************************************
       2                 :  * $Id: mrsiddataset.cpp 22753 2011-07-18 19:53:26Z 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 22753 2011-07-18 19:53:26Z 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             214 :    LTIDLLPixel(LTIColorSpace colorSpace,
     121                 :             lt_uint16 numBands,
     122             214 :             LTIDataType dataType) : T(colorSpace,numBands,dataType) {}
     123             214 :    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             130 :    LTIDLLNavigator(const LTIImage& image ) : T(image) {}
     144             130 :    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              24 :    LTIDLLCopy(const T& original) : T(original) {}
     163              24 :    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             214 : MrSIDRasterBand::MrSIDRasterBand( MrSIDDataset *poDS, int nBand )
     341                 : {
     342             214 :     this->poDS = poDS;
     343             214 :     poGDS = poDS;
     344             214 :     this->nBand = nBand;
     345             214 :     this->eDataType = poDS->eDataType;
     346                 : 
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Set the block sizes and buffer parameters.                      */
     349                 : /* -------------------------------------------------------------------- */
     350             214 :     nBlockXSize = poDS->nBlockXSize;
     351             214 :     nBlockYSize = poDS->nBlockYSize;
     352                 : //#ifdef notdef
     353             214 :     if( poDS->GetRasterXSize() > 2048 )
     354               6 :         nBlockXSize = 1024;
     355             214 :     if( poDS->GetRasterYSize() > 128 )
     356              84 :         nBlockYSize = 128;
     357                 :     else
     358             130 :         nBlockYSize = poDS->GetRasterYSize();
     359                 : //#endif
     360                 : 
     361             214 :     nBlockSize = nBlockXSize * nBlockYSize;
     362                 :     poPixel = new LTIDLLPixel<LTIPixel>( poDS->eColorSpace, poDS->nBands,
     363             214 :                                          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             214 :         dfNoDataValue = 0.0;
     419             214 :         bNoDataSet = FALSE;
     420                 :      }
     421                 : 
     422             214 :     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              82 :             eBandInterp = GCI_GrayIndex;
     465              82 :             break;
     466                 : 
     467                 :         default:
     468               6 :             eBandInterp = GCI_Undefined;
     469                 :             break;
     470                 :     }
     471             214 : }
     472                 : 
     473                 : /************************************************************************/
     474                 : /*                            ~MrSIDRasterBand()                        */
     475                 : /************************************************************************/
     476                 : 
     477             214 : MrSIDRasterBand::~MrSIDRasterBand()
     478                 : {
     479             214 :     if ( poPixel )
     480             214 :         delete poPixel;
     481             214 : }
     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             130 : MrSIDDataset::MrSIDDataset(int bIsJPEG2000)
     736                 : {
     737             130 :     poStream = NULL;
     738             130 :     poImageReader = NULL;
     739                 : #ifdef MRSID_ESDK
     740                 :     poImageWriter = NULL;
     741                 : #endif
     742             130 :     poLTINav = NULL;
     743             130 :     poMetadata = NULL;
     744             130 :     poNDPixel = NULL;
     745             130 :     eSampleType = LTI_DATATYPE_UINT8;
     746             130 :     nBands = 0;
     747             130 :     eDataType = GDT_Byte;
     748                 :     
     749             130 :     poBuffer = NULL;
     750             130 :     bPrevBlockRead = FALSE;
     751             130 :     nPrevBlockXOff = 0;
     752             130 :     nPrevBlockYOff = 0;
     753                 :     
     754             130 :     pszProjection = CPLStrdup( "" );
     755             130 :     bHasGeoTransform = FALSE;
     756             130 :     adfGeoTransform[0] = 0.0;
     757             130 :     adfGeoTransform[1] = 1.0;
     758             130 :     adfGeoTransform[2] = 0.0;
     759             130 :     adfGeoTransform[3] = 0.0;
     760             130 :     adfGeoTransform[4] = 0.0;
     761             130 :     adfGeoTransform[5] = 1.0;
     762             130 :     psDefn = NULL;
     763                 :     
     764             130 :     dfCurrentMag = 1.0;
     765             130 :     bIsOverview = FALSE;
     766             130 :     poParentDS = this;
     767             130 :     nOverviewCount = 0;
     768             130 :     papoOverviewDS = NULL;
     769                 :     
     770             130 :     poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2MrSID" : "MrSID" );
     771             130 : }
     772                 : 
     773                 : /************************************************************************/
     774                 : /*                            ~MrSIDDataset()                           */
     775                 : /************************************************************************/
     776                 : 
     777             130 : MrSIDDataset::~MrSIDDataset()
     778                 : {
     779             130 :     FlushCache();
     780                 : 
     781                 : #ifdef MRSID_ESDK
     782                 :     if ( poImageWriter )
     783                 :         delete poImageWriter;
     784                 : #endif
     785                 : 
     786             130 :     if ( poBuffer )
     787              18 :         delete poBuffer;
     788             130 :     if ( poMetadata )
     789              24 :         delete poMetadata;
     790             130 :     if ( poLTINav )
     791             130 :         delete poLTINav;
     792             130 :     if ( poImageReader && !bIsOverview )
     793                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
     794                 :     {
     795              24 :         poImageReader->release();
     796              24 :         poImageReader = NULL;
     797                 :     }
     798                 : #else
     799                 :         delete poImageReader;
     800                 : #endif
     801                 :     // points to another member, don't delete
     802             130 :     poStream = NULL;
     803                 : 
     804             130 :     if ( pszProjection )
     805             130 :         CPLFree( pszProjection );
     806             130 :     if ( psDefn )
     807              24 :         delete psDefn;
     808             130 :     CloseDependentDatasets();
     809             130 : }
     810                 : 
     811                 : /************************************************************************/
     812                 : /*                      CloseDependentDatasets()                        */
     813                 : /************************************************************************/
     814                 : 
     815             130 : int MrSIDDataset::CloseDependentDatasets()
     816                 : {
     817             130 :     int bRet = GDALPamDataset::CloseDependentDatasets();
     818                 : 
     819             130 :     if ( papoOverviewDS )
     820                 :     {
     821             129 :         for( int i = 0; i < nOverviewCount; i++ )
     822             106 :             delete papoOverviewDS[i];
     823              23 :         CPLFree( papoOverviewDS );
     824              23 :         papoOverviewDS = NULL;
     825              23 :         bRet = TRUE;
     826                 :     }
     827             130 :     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               4 : CPLErr MrSIDDataset::GetGeoTransform( double * padfTransform )
    1052                 : {
    1053               4 :     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               3 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1062               3 :         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             311 : char *MrSIDDataset::SerializeMetadataRec( const LTIMetadataRecord *poMetadataRec )
    1085                 : {
    1086             311 :     GUInt32  iNumDims = 0;
    1087             311 :     const GUInt32  *paiDims = NULL;
    1088             311 :     const void     *pData = poMetadataRec->getArrayData( iNumDims, paiDims );
    1089             311 :     GUInt32        i, j, k = 0, iLength;
    1090             311 :     char           *pszMetadata = CPLStrdup( "" );
    1091                 : 
    1092             622 :     for ( i = 0; i < iNumDims; i++ )
    1093                 :     {
    1094                 :         // stops on large binary data
    1095             311 :         if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_UINT8 
    1096               0 :              && paiDims[i] > 1024 )
    1097               0 :             return pszMetadata;
    1098                 : 
    1099             776 :         for ( j = 0; j < paiDims[i]; j++ )
    1100                 :         {
    1101             465 :             CPLString osTemp;
    1102                 : 
    1103             465 :             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             100 :                     osTemp.Printf( "%u", ((GUInt16 *)pData)[k++] );
    1111             100 :                     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              14 :                     osTemp.Printf( "%u", ((GUInt32 *)pData)[k++] );
    1117              14 :                     break;
    1118                 :                 case LTI_METADATA_DATATYPE_SINT32:
    1119              21 :                     osTemp.Printf( "%d", ((GInt32 *)pData)[k++] );
    1120              21 :                     break;
    1121                 :                 case LTI_METADATA_DATATYPE_FLOAT32:
    1122              21 :                     osTemp.Printf( "%f", ((float *)pData)[k++] );
    1123              21 :                     break;
    1124                 :                 case LTI_METADATA_DATATYPE_FLOAT64:
    1125             197 :                     osTemp.Printf( "%f", ((double *)pData)[k++] );
    1126             197 :                     break;
    1127                 :                 case LTI_METADATA_DATATYPE_ASCII:
    1128             112 :                     osTemp = ((const char **)pData)[k++];
    1129             112 :                     break;
    1130                 :                 default:
    1131               0 :                     osTemp = "";
    1132                 :                     break;
    1133                 :             }
    1134                 : 
    1135             465 :             iLength = strlen(pszMetadata) + strlen(osTemp) + 2;
    1136                 : 
    1137             465 :             pszMetadata = (char *)CPLRealloc( pszMetadata, iLength );
    1138             465 :             if ( !EQUAL( pszMetadata, "" ) )
    1139             154 :                 strncat( pszMetadata, ",", 1 );
    1140             465 :             strncat( pszMetadata, osTemp, iLength );
    1141                 :         }
    1142                 :     }
    1143                 : 
    1144             311 :     return pszMetadata;
    1145                 : }
    1146                 : 
    1147                 : /************************************************************************/
    1148                 : /*                          GetMetadataElement()                        */
    1149                 : /************************************************************************/
    1150                 : 
    1151             416 : int MrSIDDataset::GetMetadataElement( const char *pszKey, void *pValue,
    1152                 :                                       int iLength )
    1153                 : {
    1154             416 :     if ( !poMetadata->has( pszKey ) )
    1155             314 :         return FALSE;
    1156                 : 
    1157             102 :     const LTIMetadataRecord *poMetadataRec = NULL;
    1158             102 :     poMetadata->get( pszKey, poMetadataRec );
    1159                 : 
    1160             102 :     if ( !poMetadataRec->isScalar() )
    1161              28 :         return FALSE;
    1162                 : 
    1163                 :     // XXX: return FALSE if we have more than one element in metadata record
    1164                 :     int iSize;
    1165              74 :     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              66 :              iSize = 2;
    1174              66 :              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               8 :              iSize = iLength;
    1185               8 :              break;
    1186                 :          default:
    1187               0 :              iSize = 0;
    1188                 :              break;
    1189                 :     }
    1190                 : 
    1191              74 :     if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_ASCII )
    1192                 :     {
    1193                 :         strncpy( (char *)pValue,
    1194               8 :                  ((const char**)poMetadataRec->getScalarData())[0], iSize );
    1195               8 :         ((char *)pValue)[iSize - 1] = '\0';
    1196                 :     }
    1197                 :     else
    1198              66 :         memcpy( pValue, poMetadataRec->getScalarData(), iSize );
    1199                 : 
    1200              74 :     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             130 : CPLErr MrSIDDataset::OpenZoomLevel( lt_int32 iZoom )
    1222                 : {
    1223                 : /* -------------------------------------------------------------------- */
    1224                 : /*      Get image geometry.                                            */
    1225                 : /* -------------------------------------------------------------------- */
    1226             130 :     if ( iZoom != 0 )
    1227                 :     {
    1228                 :         lt_uint32 iWidth, iHeight;
    1229             106 :         dfCurrentMag = LTIUtils::levelToMag( iZoom );
    1230             106 :         poImageReader->getDimsAtMag( dfCurrentMag, iWidth, iHeight );
    1231             106 :         nRasterXSize = iWidth;
    1232             106 :         nRasterYSize = iHeight;
    1233                 :     }
    1234                 :     else
    1235                 :     {
    1236              24 :         dfCurrentMag = 1.0;
    1237              24 :         nRasterXSize = poImageReader->getWidth();
    1238              24 :         nRasterYSize = poImageReader->getHeight();
    1239                 :     }
    1240                 : 
    1241             130 :     nBands = poImageReader->getNumBands();
    1242             130 :     nBlockXSize = nRasterXSize;
    1243             130 :     nBlockYSize = poImageReader->getStripHeight();
    1244                 : 
    1245                 :     CPLDebug( "MrSID", "Opened zoom level %d with size %dx%d.",
    1246             130 :               iZoom, nRasterXSize, nRasterYSize );
    1247                 : 
    1248                 :     try
    1249                 :     {
    1250             130 :         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             130 :     eColorSpace = poImageReader->getColorSpace();
    1264             130 :     eSampleType = poImageReader->getDataType();
    1265             130 :     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             106 :         eDataType = GDT_Byte;
    1289                 :         break;
    1290                 :     }
    1291                 : 
    1292                 : /* -------------------------------------------------------------------- */
    1293                 : /*      Read georeferencing.                                            */
    1294                 : /* -------------------------------------------------------------------- */
    1295             130 :     if ( !poImageReader->isGeoCoordImplicit() )
    1296                 :     {
    1297              60 :         const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
    1298                 :         oGeo.get( adfGeoTransform[0], adfGeoTransform[3],
    1299                 :                   adfGeoTransform[1], adfGeoTransform[5],
    1300              60 :                   adfGeoTransform[2], adfGeoTransform[4] );
    1301                 :         
    1302              60 :         adfGeoTransform[0] = adfGeoTransform[0] - adfGeoTransform[1] / 2;
    1303              60 :         adfGeoTransform[3] = adfGeoTransform[3] - adfGeoTransform[5] / 2;
    1304              60 :         bHasGeoTransform = TRUE;
    1305                 :     }
    1306              70 :     else if( iZoom == 0 )
    1307                 :     {
    1308                 :         bHasGeoTransform = 
    1309              12 :             GDALReadWorldFile( GetDescription(), ".sdw",  
    1310                 :                                adfGeoTransform )
    1311              12 :             || GDALReadWorldFile( GetDescription(), ".sidw", 
    1312                 :                                   adfGeoTransform )
    1313              12 :             || GDALReadWorldFile( GetDescription(), ".wld", 
    1314              48 :                                   adfGeoTransform );
    1315                 :     }
    1316                 :     
    1317                 : /* -------------------------------------------------------------------- */
    1318                 : /*      Read wkt.                                                       */
    1319                 : /* -------------------------------------------------------------------- */
    1320                 : #ifdef MRSID_HAVE_GETWKT
    1321             130 :     if( !poImageReader->isGeoCoordImplicit() )
    1322                 :     {
    1323              60 :         const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
    1324                 :         
    1325              60 :         if( oGeo.getWKT() )
    1326                 :         {
    1327                 :             /* Workaround probable issue with GeoDSK 7 on 64bit Linux */
    1328              60 :             if (!(pszProjection != NULL && !EQUALN(pszProjection, "LOCAL_CS", 8)
    1329                 :                 && EQUALN( oGeo.getWKT(), "LOCAL_CS", 8)))
    1330                 :             {
    1331              60 :                 CPLFree( pszProjection );
    1332              60 :                 pszProjection =  CPLStrdup( oGeo.getWKT() );
    1333                 :             }
    1334                 :         }
    1335                 :     }
    1336                 : #endif // HAVE_MRSID_GETWKT
    1337                 : 
    1338                 : /* -------------------------------------------------------------------- */
    1339                 : /*      Special case for https://zulu.ssc.nasa.gov/mrsid/mrsid.pl       */
    1340                 : /*      where LandSat .SID are accompanied by a .met file with the      */
    1341                 : /*      projection                                                      */
    1342                 : /* -------------------------------------------------------------------- */
    1343             140 :     if (iZoom == 0 && (pszProjection == NULL || pszProjection[0] == '\0') &&
    1344              10 :         EQUAL(CPLGetExtension(GetDescription()), "sid"))
    1345                 :     {
    1346               0 :         const char* pszMETFilename = CPLResetExtension(GetDescription(), "met");
    1347               0 :         VSILFILE* fp = VSIFOpenL(pszMETFilename, "rb");
    1348               0 :         if (fp)
    1349                 :         {
    1350                 :             const char* pszLine;
    1351               0 :             int nCountLine = 0;
    1352               0 :             int nUTMZone = 0;
    1353               0 :             int bWGS84 = FALSE;
    1354               0 :             int bUnitsMeter = FALSE;
    1355               0 :             while ( (pszLine = CPLReadLine2L(fp, 200, NULL)) != NULL &&
    1356                 :                     ++nCountLine < 1000 )
    1357                 :             {
    1358               0 :                 if (nCountLine == 1 && strcmp(pszLine, "::MetadataFile") != 0)
    1359               0 :                     break;
    1360               0 :                 if (EQUALN(pszLine, "Projection UTM ", 15))
    1361               0 :                     nUTMZone = atoi(pszLine + 15);
    1362               0 :                 else if (EQUAL(pszLine, "Datum WGS84"))
    1363               0 :                     bWGS84 = TRUE;
    1364               0 :                 else if (EQUAL(pszLine, "Units Meters"))
    1365               0 :                     bUnitsMeter = TRUE;
    1366                 :             }
    1367               0 :             VSIFCloseL(fp);
    1368                 : 
    1369                 :             /* Images in southern hemisphere have negative northings in the */
    1370                 :             /* .sdw file. A bit weird, but anyway we must use the northern */
    1371                 :             /* UTM SRS for consistency */
    1372               0 :             if (nUTMZone >= 1 && nUTMZone <= 60 && bWGS84 && bUnitsMeter)
    1373                 :             {
    1374               0 :                 osMETFilename = pszMETFilename;
    1375                 :                 
    1376               0 :                 OGRSpatialReference oSRS;
    1377               0 :                 oSRS.importFromEPSG(32600 + nUTMZone);
    1378               0 :                 CPLFree(pszProjection);
    1379               0 :                 pszProjection = NULL;
    1380               0 :                 oSRS.exportToWkt(&pszProjection);
    1381                 :             }
    1382                 :         }
    1383                 :     }
    1384                 : 
    1385                 : /* -------------------------------------------------------------------- */
    1386                 : /*      Read NoData value.                                              */
    1387                 : /* -------------------------------------------------------------------- */
    1388             130 :     poNDPixel = poImageReader->getNoDataPixel();
    1389                 : 
    1390                 : /* -------------------------------------------------------------------- */
    1391                 : /*      Create band information objects.                                */
    1392                 : /* -------------------------------------------------------------------- */
    1393                 :     int             iBand;
    1394                 : 
    1395             688 :     for( iBand = 1; iBand <= nBands; iBand++ )
    1396             214 :         SetBand( iBand, new MrSIDRasterBand( this, iBand ) );
    1397                 : 
    1398             130 :     return CE_None;
    1399                 : }
    1400                 : 
    1401                 : /************************************************************************/
    1402                 : /*                         MrSIDIdentify()                              */
    1403                 : /*                                                                      */
    1404                 : /*          Identify method that only supports MrSID files.             */
    1405                 : /************************************************************************/
    1406                 : 
    1407           11400 : static int MrSIDIdentify( GDALOpenInfo * poOpenInfo )
    1408                 : {
    1409           11400 :     if( poOpenInfo->nHeaderBytes < 32 )
    1410           10643 :         return FALSE;
    1411                 : 
    1412             757 :     if ( !EQUALN((const char *) poOpenInfo->pabyHeader, "msid", 4) )
    1413             749 :         return FALSE;
    1414                 : 
    1415                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    1416                 :     lt_uint8 gen;
    1417                 :     bool raster;
    1418                 :     LT_STATUS eStat =
    1419               8 :         MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
    1420               8 :     if (!LT_SUCCESS(eStat) || !raster)
    1421               0 :        return FALSE;
    1422                 : #endif
    1423                 : 
    1424               8 :     return TRUE;
    1425                 : }
    1426                 : 
    1427                 : /************************************************************************/
    1428                 : /*                          MrSIDOpen()                                 */
    1429                 : /*                                                                      */
    1430                 : /*          Open method that only supports MrSID files.                 */
    1431                 : /************************************************************************/
    1432                 : 
    1433            2155 : static GDALDataset* MrSIDOpen( GDALOpenInfo *poOpenInfo )
    1434                 : {
    1435            2155 :     if (!MrSIDIdentify(poOpenInfo))
    1436            2147 :         return NULL;
    1437                 :         
    1438               8 :     return MrSIDDataset::Open( poOpenInfo, FALSE );
    1439                 : }
    1440                 : 
    1441                 : 
    1442                 : #ifdef MRSID_J2K
    1443                 : 
    1444                 : static const unsigned char jpc_header[] = 
    1445                 : {0xff,0x4f};
    1446                 : 
    1447                 : /************************************************************************/
    1448                 : /*                         JP2Identify()                                */
    1449                 : /*                                                                      */
    1450                 : /*        Identify method that only supports JPEG2000 files.            */
    1451                 : /************************************************************************/
    1452                 : 
    1453           10979 : static int JP2Identify( GDALOpenInfo *poOpenInfo )
    1454                 : {
    1455           10979 :     if( poOpenInfo->nHeaderBytes < 32 )
    1456           10541 :         return FALSE;
    1457                 : 
    1458             438 :     if( memcmp( poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header) ) == 0 )
    1459                 :     {
    1460                 :         const char *pszExtension;
    1461                 : 
    1462               9 :         pszExtension = CPLGetExtension( poOpenInfo->pszFilename );
    1463                 :         
    1464               9 :         if( !EQUAL(pszExtension,"jpc") && !EQUAL(pszExtension,"j2k") 
    1465                 :             && !EQUAL(pszExtension,"jp2") && !EQUAL(pszExtension,"jpx") 
    1466                 :             && !EQUAL(pszExtension,"j2c") && !EQUAL(pszExtension,"ntf"))
    1467               0 :             return FALSE;
    1468                 :     }
    1469             429 :     else if( !EQUALN((const char *) poOpenInfo->pabyHeader + 4, "jP  ", 4) )
    1470             422 :         return FALSE;
    1471                 : 
    1472              16 :     return TRUE;
    1473                 : }
    1474                 : 
    1475                 : /************************************************************************/
    1476                 : /*                            JP2Open()                                 */
    1477                 : /*                                                                      */
    1478                 : /*      Open method that only supports JPEG2000 files.                  */
    1479                 : /************************************************************************/
    1480                 : 
    1481            1761 : static GDALDataset* JP2Open( GDALOpenInfo *poOpenInfo )
    1482                 : {
    1483            1761 :     if (!JP2Identify(poOpenInfo))
    1484            1745 :         return NULL;
    1485                 :         
    1486              16 :     return MrSIDDataset::Open( poOpenInfo, TRUE );
    1487                 : }
    1488                 : 
    1489                 : #endif // MRSID_J2K
    1490                 : 
    1491                 : /************************************************************************/
    1492                 : /*                                Open()                                */
    1493                 : /************************************************************************/
    1494                 : 
    1495              24 : GDALDataset *MrSIDDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJP2 )
    1496                 : {
    1497              24 :     if(poOpenInfo->fp)
    1498                 :     {
    1499              18 :         VSIFClose( poOpenInfo->fp );
    1500              18 :         poOpenInfo->fp = NULL;
    1501                 :     }
    1502                 : 
    1503                 : /* -------------------------------------------------------------------- */
    1504                 : /*      Create a corresponding GDALDataset.                             */
    1505                 : /* -------------------------------------------------------------------- */
    1506                 :     MrSIDDataset    *poDS;
    1507                 :     LT_STATUS       eStat;
    1508                 : 
    1509              24 :     poDS = new MrSIDDataset(bIsJP2);
    1510                 : 
    1511                 :     // try the LTIOFileStream first, since it uses filesystem caching
    1512              24 :     eStat = poDS->oLTIStream.initialize( poOpenInfo->pszFilename, "rb" );
    1513              24 :     if ( LT_SUCCESS(eStat) )
    1514                 :     {
    1515              24 :         eStat = poDS->oLTIStream.open();
    1516              24 :         if ( LT_SUCCESS(eStat) )
    1517              18 :             poDS->poStream = &(poDS->oLTIStream);
    1518                 :     }
    1519                 : 
    1520                 :     // fall back on VSI for non-files
    1521              24 :     if ( !LT_SUCCESS(eStat) || !poDS->poStream )
    1522                 :     {
    1523               6 :         eStat = poDS->oVSIStream.initialize( poOpenInfo->pszFilename, "rb" );
    1524               6 :         if ( !LT_SUCCESS(eStat) )
    1525                 :         {
    1526                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1527                 :                       "LTIVSIStream::initialize(): "
    1528                 :                       "failed to open file \"%s\".\n%s",
    1529               0 :                       poOpenInfo->pszFilename, getLastStatusString( eStat ) );
    1530               0 :             delete poDS;
    1531               0 :             return NULL;
    1532                 :         }
    1533                 : 
    1534               6 :         eStat = poDS->oVSIStream.open();
    1535               6 :         if ( !LT_SUCCESS(eStat) )
    1536                 :         {
    1537                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1538                 :                       "LTIVSIStream::open(): "
    1539                 :                       "failed to open file \"%s\".\n%s",
    1540               0 :                       poOpenInfo->pszFilename, getLastStatusString( eStat ) );
    1541               0 :             delete poDS;
    1542               0 :             return NULL;
    1543                 :         }
    1544                 : 
    1545               6 :         poDS->poStream = &(poDS->oVSIStream);
    1546                 :     }
    1547                 : 
    1548                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
    1549                 : 
    1550                 : #ifdef MRSID_J2K
    1551              24 :     if ( bIsJP2 )
    1552                 :     {
    1553              16 :         J2KImageReader  *reader = J2KImageReader::create();
    1554              16 :         eStat = reader->initialize( *(poDS->poStream) );
    1555              16 :         poDS->poImageReader = reader;
    1556                 :     }
    1557                 :     else
    1558                 : #endif /* MRSID_J2K */
    1559                 :     {
    1560               8 :         MrSIDImageReader    *reader = MrSIDImageReader::create();
    1561               8 :         eStat = reader->initialize( poDS->poStream, NULL );
    1562               8 :         poDS->poImageReader = reader;           
    1563                 :     }
    1564                 : 
    1565                 : #else /* LTI_SDK_MAJOR < 7 */
    1566                 : 
    1567                 : #ifdef MRSID_J2K
    1568                 :     if ( bIsJP2 )
    1569                 :     {
    1570                 :         poDS->poImageReader =
    1571                 :             new LTIDLLReader<J2KImageReader>( *(poDS->poStream), true );
    1572                 :         eStat = poDS->poImageReader->initialize();
    1573                 :     }
    1574                 :     else
    1575                 : #endif /* MRSID_J2K */
    1576                 :     {
    1577                 :         poDS->poImageReader =
    1578                 :             new LTIDLLReader<MrSIDImageReader>( poDS->poStream, NULL );
    1579                 :         eStat = poDS->poImageReader->initialize();
    1580                 :     }
    1581                 : 
    1582                 : #endif /* LTI_SDK_MAJOR >= 7 */
    1583                 : 
    1584              24 :     if ( !LT_SUCCESS(eStat) )
    1585                 :     {
    1586                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1587                 :                   "LTIImageReader::initialize(): "
    1588                 :                   "failed to initialize reader from the stream \"%s\".\n%s",
    1589               0 :                   poOpenInfo->pszFilename, getLastStatusString( eStat ) );
    1590               0 :         delete poDS;
    1591               0 :         return NULL;
    1592                 :     }
    1593                 : 
    1594                 : /* -------------------------------------------------------------------- */
    1595                 : /*      Read metadata.                                                  */
    1596                 : /* -------------------------------------------------------------------- */
    1597                 :     poDS->poMetadata = new LTIDLLCopy<LTIMetadataDatabase>(
    1598              24 :         poDS->poImageReader->getMetadata() );
    1599              24 :     const GUInt32       iNumRecs = poDS->poMetadata->getIndexCount();
    1600                 :     GUInt32             i;
    1601                 : 
    1602             335 :     for ( i = 0; i < iNumRecs; i++ )
    1603                 :     {
    1604             311 :         const LTIMetadataRecord *poMetadataRec = NULL;
    1605             311 :         if ( LT_SUCCESS(poDS->poMetadata->getDataByIndex(i, poMetadataRec)) )
    1606                 :         {
    1607             311 :             char    *pszElement = poDS->SerializeMetadataRec( poMetadataRec );
    1608             311 :             char    *pszKey = CPLStrdup( poMetadataRec->getTagName() );
    1609             311 :             char    *pszTemp = pszKey;
    1610                 : 
    1611                 :             // GDAL metadata keys should not contain ':' and '=' characters.
    1612                 :             // We will replace them with '_'.
    1613           10196 :             do
    1614                 :             {
    1615           10196 :                 if ( *pszTemp == ':' || *pszTemp == '=' )
    1616             888 :                     *pszTemp = '_';
    1617                 :             }
    1618                 :             while ( *++pszTemp );
    1619                 : 
    1620             311 :             poDS->SetMetadataItem( pszKey, pszElement );
    1621                 : 
    1622             311 :             CPLFree( pszElement );
    1623             311 :             CPLFree( pszKey );
    1624                 :         }
    1625                 :     }
    1626                 : 
    1627                 : /* -------------------------------------------------------------------- */
    1628                 : /*      Add MrSID version.                                              */
    1629                 : /* -------------------------------------------------------------------- */
    1630                 : #ifdef MRSID_J2K
    1631              24 :     if( !bIsJP2 )
    1632                 : #endif
    1633                 :     {
    1634                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    1635                 :         lt_uint8 gen;
    1636                 :         bool raster;
    1637               8 :         MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
    1638               8 :         poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d%s", gen, raster ? "" : " LiDAR") );
    1639                 : #else
    1640                 :         lt_uint8 major;
    1641                 :         lt_uint8 minor;
    1642                 :         char letter;
    1643                 :         MrSIDImageReader* poMrSIDImageReader = (MrSIDImageReader*)poDS->poImageReader;
    1644                 :         poMrSIDImageReader->getVersion(major, minor, minor, letter);
    1645                 :         if (major < 2) 
    1646                 :             major = 2;
    1647                 :         poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d", major) );
    1648                 : #endif
    1649                 :     }
    1650                 : 
    1651              24 :     poDS->GetGTIFDefn();
    1652                 :     
    1653                 : /* -------------------------------------------------------------------- */
    1654                 : /*      Get number of resolution levels (we will use them as overviews).*/
    1655                 : /* -------------------------------------------------------------------- */
    1656                 : #ifdef MRSID_J2K
    1657              24 :     if( bIsJP2 )
    1658                 :         poDS->nOverviewCount
    1659              16 :             = ((J2KImageReader *) (poDS->poImageReader))->getNumLevels();
    1660                 :     else
    1661                 : #endif
    1662                 :         poDS->nOverviewCount
    1663               8 :             = ((MrSIDImageReader *) (poDS->poImageReader))->getNumLevels();
    1664                 : 
    1665              24 :     if ( poDS->nOverviewCount > 0 )
    1666                 :     {
    1667                 :         lt_int32        i;
    1668                 : 
    1669                 :         poDS->papoOverviewDS = (MrSIDDataset **)
    1670              23 :             CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) );
    1671                 : 
    1672             258 :         for ( i = 0; i < poDS->nOverviewCount; i++ )
    1673                 :         {
    1674             106 :             poDS->papoOverviewDS[i] = new MrSIDDataset(bIsJP2);
    1675             106 :             poDS->papoOverviewDS[i]->poImageReader = poDS->poImageReader;
    1676             106 :             poDS->papoOverviewDS[i]->OpenZoomLevel( i + 1 );
    1677             106 :             poDS->papoOverviewDS[i]->bIsOverview = TRUE;
    1678             106 :             poDS->papoOverviewDS[i]->poParentDS = poDS;
    1679                 :         }
    1680                 :     }
    1681                 : 
    1682                 : /* -------------------------------------------------------------------- */
    1683                 : /*      Create object for the whole image.                              */
    1684                 : /* -------------------------------------------------------------------- */
    1685              24 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1686              24 :     poDS->OpenZoomLevel( 0 );
    1687                 : 
    1688                 :     CPLDebug( "MrSID",
    1689                 :               "Opened image: width %d, height %d, bands %d",
    1690              24 :               poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands );
    1691                 : 
    1692              24 :     if( poDS->nBands > 1 )
    1693               7 :         poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
    1694                 : 
    1695              24 :     if (bIsJP2)
    1696                 :     {
    1697              16 :         GDALJP2Metadata oJP2Geo;
    1698              16 :         if ( oJP2Geo.ReadAndParse( poOpenInfo->pszFilename ) )
    1699                 :         {
    1700                 :             /*poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
    1701                 :             poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
    1702                 :             memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
    1703                 :                     sizeof(double) * 6 );
    1704                 :             poDS->nGCPCount = oJP2Geo.nGCPCount;
    1705                 :             poDS->pasGCPList = oJP2Geo.pasGCPList;
    1706                 :             oJP2Geo.pasGCPList = NULL;
    1707                 :             oJP2Geo.nGCPCount = 0;*/
    1708                 :         }
    1709                 : 
    1710              16 :         if (oJP2Geo.pszXMPMetadata)
    1711                 :         {
    1712                 :             char *apszMDList[2];
    1713               1 :             apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
    1714               1 :             apszMDList[1] = NULL;
    1715               1 :             poDS->SetMetadata(apszMDList, "xml:XMP");
    1716              16 :         }
    1717                 :     }
    1718                 : 
    1719                 : /* -------------------------------------------------------------------- */
    1720                 : /*      Initialize any PAM information.                                 */
    1721                 : /* -------------------------------------------------------------------- */
    1722              24 :     poDS->TryLoadXML();
    1723                 : 
    1724                 : /* -------------------------------------------------------------------- */
    1725                 : /*      Initialize the overview manager for mask band support.          */
    1726                 : /* -------------------------------------------------------------------- */
    1727              24 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    1728                 : 
    1729              24 :     return( poDS );
    1730                 : }
    1731                 : 
    1732                 : /************************************************************************/
    1733                 : /*                    EPSGProjMethodToCTProjMethod()                    */
    1734                 : /*                                                                      */
    1735                 : /*      Convert between the EPSG enumeration for projection methods,    */
    1736                 : /*      and the GeoTIFF CT codes.                                       */
    1737                 : /*      Explicitly copied from geo_normalize.c of the GeoTIFF package   */
    1738                 : /************************************************************************/
    1739                 : 
    1740               4 : static int EPSGProjMethodToCTProjMethod( int nEPSG )
    1741                 : 
    1742                 : {
    1743                 :     /* see trf_method.csv for list of EPSG codes */
    1744                 :     
    1745               4 :     switch( nEPSG )
    1746                 :     {
    1747                 :       case 9801:
    1748               0 :         return( CT_LambertConfConic_1SP );
    1749                 : 
    1750                 :       case 9802:
    1751               0 :         return( CT_LambertConfConic_2SP );
    1752                 : 
    1753                 :       case 9803:
    1754               0 :         return( CT_LambertConfConic_2SP ); /* Belgian variant not supported */
    1755                 : 
    1756                 :       case 9804:
    1757               0 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
    1758                 : 
    1759                 :       case 9805:
    1760               0 :         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
    1761                 : 
    1762                 :       case 9806:
    1763               0 :         return( CT_CassiniSoldner );
    1764                 : 
    1765                 :       case 9807:
    1766               4 :         return( CT_TransverseMercator );
    1767                 : 
    1768                 :       case 9808:
    1769               0 :         return( CT_TransvMercator_SouthOriented );
    1770                 : 
    1771                 :       case 9809:
    1772               0 :         return( CT_ObliqueStereographic );
    1773                 : 
    1774                 :       case 9810:
    1775               0 :         return( CT_PolarStereographic );
    1776                 : 
    1777                 :       case 9811:
    1778               0 :         return( CT_NewZealandMapGrid );
    1779                 : 
    1780                 :       case 9812:
    1781               0 :         return( CT_ObliqueMercator ); /* is hotine actually different? */
    1782                 : 
    1783                 :       case 9813:
    1784               0 :         return( CT_ObliqueMercator_Laborde );
    1785                 : 
    1786                 :       case 9814:
    1787               0 :         return( CT_ObliqueMercator_Rosenmund ); /* swiss  */
    1788                 : 
    1789                 :       case 9815:
    1790               0 :         return( CT_ObliqueMercator );
    1791                 : 
    1792                 :       case 9816: /* tunesia mining grid has no counterpart */
    1793               0 :         return( KvUserDefined );
    1794                 :     }
    1795                 : 
    1796               0 :     return( KvUserDefined );
    1797                 : }
    1798                 : 
    1799                 : /* EPSG Codes for projection parameters.  Unfortunately, these bear no
    1800                 :    relationship to the GeoTIFF codes even though the names are so similar. */
    1801                 : 
    1802                 : #define EPSGNatOriginLat         8801
    1803                 : #define EPSGNatOriginLong        8802
    1804                 : #define EPSGNatOriginScaleFactor 8805
    1805                 : #define EPSGFalseEasting         8806
    1806                 : #define EPSGFalseNorthing        8807
    1807                 : #define EPSGProjCenterLat        8811
    1808                 : #define EPSGProjCenterLong       8812
    1809                 : #define EPSGAzimuth              8813
    1810                 : #define EPSGAngleRectifiedToSkewedGrid 8814
    1811                 : #define EPSGInitialLineScaleFactor 8815
    1812                 : #define EPSGProjCenterEasting    8816
    1813                 : #define EPSGProjCenterNorthing   8817
    1814                 : #define EPSGPseudoStdParallelLat 8818
    1815                 : #define EPSGPseudoStdParallelScaleFactor 8819
    1816                 : #define EPSGFalseOriginLat       8821
    1817                 : #define EPSGFalseOriginLong      8822
    1818                 : #define EPSGStdParallel1Lat      8823
    1819                 : #define EPSGStdParallel2Lat      8824
    1820                 : #define EPSGFalseOriginEasting   8826
    1821                 : #define EPSGFalseOriginNorthing  8827
    1822                 : #define EPSGSphericalOriginLat   8828
    1823                 : #define EPSGSphericalOriginLong  8829
    1824                 : #define EPSGInitialLongitude     8830
    1825                 : #define EPSGZoneWidth            8831
    1826                 : 
    1827                 : /************************************************************************/
    1828                 : /*                            SetGTParmIds()                            */
    1829                 : /*                                                                      */
    1830                 : /*      This is hardcoded logic to set the GeoTIFF parameter            */
    1831                 : /*      identifiers for all the EPSG supported projections.  As the     */
    1832                 : /*      trf_method.csv table grows with new projections, this code      */
    1833                 : /*      will need to be updated.                                        */
    1834                 : /*      Explicitly copied from geo_normalize.c of the GeoTIFF package.  */
    1835                 : /************************************************************************/
    1836                 : 
    1837               4 : static int SetGTParmIds( int nCTProjection, 
    1838                 :                          int *panProjParmId, 
    1839                 :                          int *panEPSGCodes )
    1840                 : 
    1841                 : {
    1842                 :     int anWorkingDummy[7];
    1843                 : 
    1844               4 :     if( panEPSGCodes == NULL )
    1845               4 :         panEPSGCodes = anWorkingDummy;
    1846               4 :     if( panProjParmId == NULL )
    1847               0 :         panProjParmId = anWorkingDummy;
    1848                 : 
    1849               4 :     memset( panEPSGCodes, 0, sizeof(int) * 7 );
    1850                 : 
    1851                 :     /* psDefn->nParms = 7; */
    1852                 :     
    1853               4 :     switch( nCTProjection )
    1854                 :     {
    1855                 :       case CT_CassiniSoldner:
    1856                 :       case CT_NewZealandMapGrid:
    1857               0 :         panProjParmId[0] = ProjNatOriginLatGeoKey;
    1858               0 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1859               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1860               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1861                 : 
    1862               0 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1863               0 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1864               0 :         panEPSGCodes[5] = EPSGFalseEasting;
    1865               0 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1866               0 :         return TRUE;
    1867                 : 
    1868                 :       case CT_ObliqueMercator:
    1869               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1870               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1871               0 :         panProjParmId[2] = ProjAzimuthAngleGeoKey;
    1872               0 :         panProjParmId[3] = ProjRectifiedGridAngleGeoKey;
    1873               0 :         panProjParmId[4] = ProjScaleAtCenterGeoKey;
    1874               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1875               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1876                 : 
    1877               0 :         panEPSGCodes[0] = EPSGProjCenterLat;
    1878               0 :         panEPSGCodes[1] = EPSGProjCenterLong;
    1879               0 :         panEPSGCodes[2] = EPSGAzimuth;
    1880               0 :         panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
    1881               0 :         panEPSGCodes[4] = EPSGInitialLineScaleFactor;
    1882               0 :         panEPSGCodes[5] = EPSGProjCenterEasting;
    1883               0 :         panEPSGCodes[6] = EPSGProjCenterNorthing;
    1884               0 :         return TRUE;
    1885                 : 
    1886                 :       case CT_ObliqueMercator_Laborde:
    1887               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1888               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1889               0 :         panProjParmId[2] = ProjAzimuthAngleGeoKey;
    1890               0 :         panProjParmId[4] = ProjScaleAtCenterGeoKey;
    1891               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1892               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1893                 : 
    1894               0 :         panEPSGCodes[0] = EPSGProjCenterLat;
    1895               0 :         panEPSGCodes[1] = EPSGProjCenterLong;
    1896               0 :         panEPSGCodes[2] = EPSGAzimuth;
    1897               0 :         panEPSGCodes[4] = EPSGInitialLineScaleFactor;
    1898               0 :         panEPSGCodes[5] = EPSGProjCenterEasting;
    1899               0 :         panEPSGCodes[6] = EPSGProjCenterNorthing;
    1900               0 :         return TRUE;
    1901                 :         
    1902                 :       case CT_LambertConfConic_1SP:
    1903                 :       case CT_Mercator:
    1904                 :       case CT_ObliqueStereographic:
    1905                 :       case CT_PolarStereographic:
    1906                 :       case CT_TransverseMercator:
    1907                 :       case CT_TransvMercator_SouthOriented:
    1908               4 :         panProjParmId[0] = ProjNatOriginLatGeoKey;
    1909               4 :         panProjParmId[1] = ProjNatOriginLongGeoKey;
    1910               4 :         panProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    1911               4 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1912               4 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1913                 : 
    1914               4 :         panEPSGCodes[0] = EPSGNatOriginLat;
    1915               4 :         panEPSGCodes[1] = EPSGNatOriginLong;
    1916               4 :         panEPSGCodes[4] = EPSGNatOriginScaleFactor;
    1917               4 :         panEPSGCodes[5] = EPSGFalseEasting;
    1918               4 :         panEPSGCodes[6] = EPSGFalseNorthing;
    1919               4 :         return TRUE;
    1920                 : 
    1921                 :       case CT_LambertConfConic_2SP:
    1922               0 :         panProjParmId[0] = ProjFalseOriginLatGeoKey;
    1923               0 :         panProjParmId[1] = ProjFalseOriginLongGeoKey;
    1924               0 :         panProjParmId[2] = ProjStdParallel1GeoKey;
    1925               0 :         panProjParmId[3] = ProjStdParallel2GeoKey;
    1926               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1927               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1928                 : 
    1929               0 :         panEPSGCodes[0] = EPSGFalseOriginLat;
    1930               0 :         panEPSGCodes[1] = EPSGFalseOriginLong;
    1931               0 :         panEPSGCodes[2] = EPSGStdParallel1Lat;
    1932               0 :         panEPSGCodes[3] = EPSGStdParallel2Lat;
    1933               0 :         panEPSGCodes[5] = EPSGFalseOriginEasting;
    1934               0 :         panEPSGCodes[6] = EPSGFalseOriginNorthing;
    1935               0 :         return TRUE;
    1936                 : 
    1937                 :       case CT_SwissObliqueCylindrical:
    1938               0 :         panProjParmId[0] = ProjCenterLatGeoKey;
    1939               0 :         panProjParmId[1] = ProjCenterLongGeoKey;
    1940               0 :         panProjParmId[5] = ProjFalseEastingGeoKey;
    1941               0 :         panProjParmId[6] = ProjFalseNorthingGeoKey;
    1942                 : 
    1943                 :         /* EPSG codes? */
    1944               0 :         return TRUE;
    1945                 : 
    1946                 :       default:
    1947               0 :         return( FALSE );
    1948                 :     }
    1949                 : }
    1950                 : 
    1951                 : static const char *papszDatumEquiv[] =
    1952                 : {
    1953                 :     "Militar_Geographische_Institut",
    1954                 :     "Militar_Geographische_Institute",
    1955                 :     "World_Geodetic_System_1984",
    1956                 :     "WGS_1984",
    1957                 :     "WGS_72_Transit_Broadcast_Ephemeris",
    1958                 :     "WGS_1972_Transit_Broadcast_Ephemeris",
    1959                 :     "World_Geodetic_System_1972",
    1960                 :     "WGS_1972",
    1961                 :     "European_Terrestrial_Reference_System_89",
    1962                 :     "European_Reference_System_1989",
    1963                 :     NULL
    1964                 : };
    1965                 : 
    1966                 : /************************************************************************/
    1967                 : /*                          WKTMassageDatum()                           */
    1968                 : /*                                                                      */
    1969                 : /*      Massage an EPSG datum name into WMT format.  Also transform     */
    1970                 : /*      specific exception cases into WKT versions.                     */
    1971                 : /*      Explicitly copied from the gt_wkt_srs.cpp.                      */
    1972                 : /************************************************************************/
    1973                 : 
    1974              13 : static void WKTMassageDatum( char ** ppszDatum )
    1975                 : 
    1976                 : {
    1977                 :     int         i, j;
    1978              13 :     char        *pszDatum = *ppszDatum;
    1979                 : 
    1980              13 :     if (pszDatum[0] == '\0')
    1981               0 :         return;
    1982                 : 
    1983                 : /* -------------------------------------------------------------------- */
    1984                 : /*      Translate non-alphanumeric values to underscores.               */
    1985                 : /* -------------------------------------------------------------------- */
    1986             340 :     for( i = 0; pszDatum[i] != '\0'; i++ )
    1987                 :     {
    1988             955 :         if( !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
    1989             485 :             && !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
    1990             143 :             && !(pszDatum[i] >= '0' && pszDatum[i] <= '9') )
    1991                 :         {
    1992              39 :             pszDatum[i] = '_';
    1993                 :         }
    1994                 :     }
    1995                 : 
    1996                 : /* -------------------------------------------------------------------- */
    1997                 : /*      Remove repeated and trailing underscores.                       */
    1998                 : /* -------------------------------------------------------------------- */
    1999             327 :     for( i = 1, j = 0; pszDatum[i] != '\0'; i++ )
    2000                 :     {
    2001             314 :         if( pszDatum[j] == '_' && pszDatum[i] == '_' )
    2002               0 :             continue;
    2003                 : 
    2004             314 :         pszDatum[++j] = pszDatum[i];
    2005                 :     }
    2006              13 :     if( pszDatum[j] == '_' )
    2007               0 :         pszDatum[j] = '\0';
    2008                 :     else
    2009              13 :         pszDatum[j+1] = '\0';
    2010                 :     
    2011                 : /* -------------------------------------------------------------------- */
    2012                 : /*      Search for datum equivelences.  Specific massaged names get     */
    2013                 : /*      mapped to OpenGIS specified names.                              */
    2014                 : /* -------------------------------------------------------------------- */
    2015              70 :     for( i = 0; papszDatumEquiv[i] != NULL; i += 2 )
    2016                 :     {
    2017              59 :         if( EQUAL(*ppszDatum,papszDatumEquiv[i]) )
    2018                 :         {
    2019               2 :             CPLFree( *ppszDatum );
    2020               2 :             *ppszDatum = CPLStrdup( papszDatumEquiv[i+1] );
    2021               2 :             return;
    2022                 :         }
    2023                 :     }
    2024                 : }
    2025                 : 
    2026                 : /************************************************************************/
    2027                 : /*                           FetchProjParms()                           */
    2028                 : /*                                                                      */
    2029                 : /*      Fetch the projection parameters for a particular projection     */
    2030                 : /*      from MrSID metadata, and fill the GTIFDefn structure out        */
    2031                 : /*      with them.                                                      */
    2032                 : /*      Copied from geo_normalize.c of the GeoTIFF package.             */
    2033                 : /************************************************************************/
    2034                 : 
    2035               7 : void MrSIDDataset::FetchProjParms()
    2036                 : {
    2037               7 :     double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
    2038               7 :     double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
    2039               7 :     double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
    2040                 : 
    2041                 : /* -------------------------------------------------------------------- */
    2042                 : /*      Get the false easting, and northing if available.               */
    2043                 : /* -------------------------------------------------------------------- */
    2044               7 :     if( !GetMetadataElement( "GEOTIFF_NUM::3082::ProjFalseEastingGeoKey",
    2045                 :                              &dfFalseEasting )
    2046                 :         && !GetMetadataElement( "GEOTIFF_NUM::3090:ProjCenterEastingGeoKey",
    2047                 :                                 &dfFalseEasting ) )
    2048               7 :         dfFalseEasting = 0.0;
    2049                 :         
    2050               7 :     if( !GetMetadataElement( "GEOTIFF_NUM::3083::ProjFalseNorthingGeoKey",
    2051                 :                              &dfFalseNorthing )
    2052                 :         && !GetMetadataElement( "GEOTIFF_NUM::3091::ProjCenterNorthingGeoKey",
    2053                 :                                 &dfFalseNorthing ) )
    2054               7 :         dfFalseNorthing = 0.0;
    2055                 : 
    2056               7 :     switch( psDefn->CTProjection )
    2057                 :     {
    2058                 : /* -------------------------------------------------------------------- */
    2059                 :       case CT_Stereographic:
    2060                 : /* -------------------------------------------------------------------- */
    2061               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2062                 :                                 &dfNatOriginLong ) == 0
    2063                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2064                 :                                    &dfNatOriginLong ) == 0
    2065                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
    2066                 :                                    &dfNatOriginLong ) == 0 )
    2067               0 :             dfNatOriginLong = 0.0;
    2068                 : 
    2069               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2070                 :                                 &dfNatOriginLat ) == 0
    2071                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2072                 :                                    &dfNatOriginLat ) == 0
    2073                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2074                 :                                    &dfNatOriginLat ) == 0 )
    2075               0 :             dfNatOriginLat = 0.0;
    2076                 : 
    2077               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2078                 :                                 &dfNatOriginScale ) == 0 )
    2079               0 :             dfNatOriginScale = 1.0;
    2080                 :             
    2081                 :         /* notdef: should transform to decimal degrees at this point */
    2082                 : 
    2083               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2084               0 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    2085               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2086               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2087               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2088               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2089               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2090               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2091               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2092               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2093                 : 
    2094               0 :         psDefn->nParms = 7;
    2095               0 :         break;
    2096                 : 
    2097                 : /* -------------------------------------------------------------------- */
    2098                 :       case CT_LambertConfConic_1SP:
    2099                 :       case CT_Mercator:
    2100                 :       case CT_ObliqueStereographic:
    2101                 :       case CT_TransverseMercator:
    2102                 :       case CT_TransvMercator_SouthOriented:
    2103                 : /* -------------------------------------------------------------------- */
    2104               7 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2105                 :                                 &dfNatOriginLong ) == 0
    2106                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2107                 :                                    &dfNatOriginLong ) == 0
    2108                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2109                 :                                    &dfNatOriginLong ) == 0 )
    2110               7 :             dfNatOriginLong = 0.0;
    2111                 : 
    2112               7 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2113                 :                                 &dfNatOriginLat ) == 0
    2114                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2115                 :                                    &dfNatOriginLat ) == 0
    2116                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2117                 :                                    &dfNatOriginLat ) == 0 )
    2118               7 :             dfNatOriginLat = 0.0;
    2119                 : 
    2120               7 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2121                 :                                 &dfNatOriginScale ) == 0 )
    2122               7 :             dfNatOriginScale = 1.0;
    2123                 : 
    2124                 :         /* notdef: should transform to decimal degrees at this point */
    2125                 : 
    2126               7 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2127               7 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2128               7 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2129               7 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2130               7 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2131               7 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2132               7 :         psDefn->ProjParm[5] = dfFalseEasting;
    2133               7 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2134               7 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2135               7 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2136                 : 
    2137               7 :         psDefn->nParms = 7;
    2138               7 :         break;
    2139                 : 
    2140                 : /* -------------------------------------------------------------------- */
    2141                 :       case CT_ObliqueMercator: /* hotine */
    2142                 : /* -------------------------------------------------------------------- */
    2143               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2144                 :                                 &dfNatOriginLong ) == 0
    2145                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2146                 :                                    &dfNatOriginLong ) == 0
    2147                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2148                 :                                    &dfNatOriginLong ) == 0 )
    2149               0 :             dfNatOriginLong = 0.0;
    2150                 : 
    2151               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2152                 :                                 &dfNatOriginLat ) == 0
    2153                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2154                 :                                    &dfNatOriginLat ) == 0
    2155                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2156                 :                                    &dfNatOriginLat ) == 0 )
    2157               0 :             dfNatOriginLat = 0.0;
    2158                 : 
    2159               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3094::ProjAzimuthAngleGeoKey",
    2160                 :                                 &dfAzimuth ) == 0 )
    2161               0 :             dfAzimuth = 0.0;
    2162                 : 
    2163               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3096::ProjRectifiedGridAngleGeoKey",
    2164                 :                                 &dfRectGridAngle ) == 0 )
    2165               0 :             dfRectGridAngle = 90.0;
    2166                 : 
    2167               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2168                 :                                 &dfNatOriginScale ) == 0
    2169                 :             && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
    2170                 :                                    &dfNatOriginScale ) == 0 )
    2171               0 :             dfNatOriginScale = 1.0;
    2172                 :             
    2173                 :         /* notdef: should transform to decimal degrees at this point */
    2174                 : 
    2175               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2176               0 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    2177               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2178               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2179               0 :         psDefn->ProjParm[2] = dfAzimuth;
    2180               0 :         psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
    2181               0 :         psDefn->ProjParm[3] = dfRectGridAngle;
    2182               0 :         psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
    2183               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2184               0 :         psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
    2185               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2186               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2187               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2188               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2189                 : 
    2190               0 :         psDefn->nParms = 7;
    2191               0 :         break;
    2192                 : 
    2193                 : /* -------------------------------------------------------------------- */
    2194                 :       case CT_CassiniSoldner:
    2195                 :       case CT_Polyconic:
    2196                 : /* -------------------------------------------------------------------- */
    2197               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2198                 :                                 &dfNatOriginLong ) == 0
    2199                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2200                 :                                    &dfNatOriginLong ) == 0
    2201                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2202                 :                                    &dfNatOriginLong ) == 0 )
    2203               0 :             dfNatOriginLong = 0.0;
    2204                 : 
    2205               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2206                 :                                 &dfNatOriginLat ) == 0
    2207                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2208                 :                                    &dfNatOriginLat ) == 0
    2209                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2210                 :                                    &dfNatOriginLat ) == 0 )
    2211               0 :             dfNatOriginLat = 0.0;
    2212                 : 
    2213                 : 
    2214               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2215                 :                                 &dfNatOriginScale ) == 0
    2216                 :             && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
    2217                 :                                    &dfNatOriginScale ) == 0 )
    2218               0 :             dfNatOriginScale = 1.0;
    2219                 :             
    2220                 :         /* notdef: should transform to decimal degrees at this point */
    2221                 : 
    2222               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2223               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2224               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2225               0 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2226               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2227               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2228               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2229               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2230               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2231               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2232                 : 
    2233               0 :         psDefn->nParms = 7;
    2234               0 :         break;
    2235                 : 
    2236                 : /* -------------------------------------------------------------------- */
    2237                 :       case CT_AzimuthalEquidistant:
    2238                 :       case CT_MillerCylindrical:
    2239                 :       case CT_Equirectangular:
    2240                 :       case CT_Gnomonic:
    2241                 :       case CT_LambertAzimEqualArea:
    2242                 :       case CT_Orthographic:
    2243                 : /* -------------------------------------------------------------------- */
    2244               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2245                 :                                 &dfNatOriginLong ) == 0
    2246                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2247                 :                                    &dfNatOriginLong ) == 0
    2248                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2249                 :                                    &dfNatOriginLong ) == 0 )
    2250               0 :             dfNatOriginLong = 0.0;
    2251                 : 
    2252               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2253                 :                                 &dfNatOriginLat ) == 0
    2254                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2255                 :                                    &dfNatOriginLat ) == 0
    2256                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2257                 :                                    &dfNatOriginLat ) == 0 )
    2258               0 :             dfNatOriginLat = 0.0;
    2259                 : 
    2260                 :         /* notdef: should transform to decimal degrees at this point */
    2261                 : 
    2262               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2263               0 :         psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
    2264               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2265               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2266               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2267               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2268               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2269               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2270                 : 
    2271               0 :         psDefn->nParms = 7;
    2272               0 :         break;
    2273                 : 
    2274                 : /* -------------------------------------------------------------------- */
    2275                 :       case CT_Robinson:
    2276                 :       case CT_Sinusoidal:
    2277                 :       case CT_VanDerGrinten:
    2278                 : /* -------------------------------------------------------------------- */
    2279               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2280                 :                                 &dfNatOriginLong ) == 0
    2281                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2282                 :                                    &dfNatOriginLong ) == 0
    2283                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2284                 :                                    &dfNatOriginLong ) == 0 )
    2285               0 :             dfNatOriginLong = 0.0;
    2286                 : 
    2287                 :         /* notdef: should transform to decimal degrees at this point */
    2288                 : 
    2289               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2290               0 :         psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
    2291               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2292               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2293               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2294               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2295                 : 
    2296               0 :         psDefn->nParms = 7;
    2297               0 :         break;
    2298                 : 
    2299                 : /* -------------------------------------------------------------------- */
    2300                 :       case CT_PolarStereographic:
    2301                 : /* -------------------------------------------------------------------- */
    2302               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3095::ProjStraightVertPoleLongGeoKey",
    2303                 :                                 &dfNatOriginLong ) == 0
    2304                 :             && GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2305                 :                                    &dfNatOriginLong ) == 0
    2306                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2307                 :                                    &dfNatOriginLong ) == 0
    2308                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
    2309                 :                                    &dfNatOriginLong ) == 0 )
    2310               0 :             dfNatOriginLong = 0.0;
    2311                 : 
    2312               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2313                 :                                 &dfNatOriginLat ) == 0
    2314                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2315                 :                                    &dfNatOriginLat ) == 0
    2316                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2317                 :                                    &dfNatOriginLat ) == 0 )
    2318               0 :             dfNatOriginLat = 0.0;
    2319                 : 
    2320               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
    2321                 :                                 &dfNatOriginScale ) == 0
    2322                 :             && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
    2323                 :                                    &dfNatOriginScale ) == 0 )
    2324               0 :             dfNatOriginScale = 1.0;
    2325                 :             
    2326                 :         /* notdef: should transform to decimal degrees at this point */
    2327                 : 
    2328               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2329               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;;
    2330               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2331               0 :         psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
    2332               0 :         psDefn->ProjParm[4] = dfNatOriginScale;
    2333               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2334               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2335               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2336               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2337               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2338                 : 
    2339               0 :         psDefn->nParms = 7;
    2340               0 :         break;
    2341                 : 
    2342                 : /* -------------------------------------------------------------------- */
    2343                 :       case CT_LambertConfConic_2SP:
    2344                 : /* -------------------------------------------------------------------- */
    2345               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
    2346                 :                                 &dfStdParallel1 ) == 0 )
    2347               0 :             dfStdParallel1 = 0.0;
    2348                 : 
    2349               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
    2350                 :                                 &dfStdParallel2 ) == 0 )
    2351               0 :             dfStdParallel1 = 0.0;
    2352                 : 
    2353               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2354                 :                                 &dfNatOriginLong ) == 0
    2355                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2356                 :                                    &dfNatOriginLong ) == 0
    2357                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2358                 :                                    &dfNatOriginLong ) == 0 )
    2359               0 :             dfNatOriginLong = 0.0;
    2360                 : 
    2361               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2362                 :                                 &dfNatOriginLat ) == 0
    2363                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2364                 :                                    &dfNatOriginLat ) == 0
    2365                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2366                 :                                    &dfNatOriginLat ) == 0 )
    2367               0 :             dfNatOriginLat = 0.0;
    2368                 : 
    2369                 :         /* notdef: should transform to decimal degrees at this point */
    2370                 : 
    2371               0 :         psDefn->ProjParm[0] = dfNatOriginLat;
    2372               0 :         psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
    2373               0 :         psDefn->ProjParm[1] = dfNatOriginLong;
    2374               0 :         psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
    2375               0 :         psDefn->ProjParm[2] = dfStdParallel1;
    2376               0 :         psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
    2377               0 :         psDefn->ProjParm[3] = dfStdParallel2;
    2378               0 :         psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
    2379               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2380               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2381               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2382               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2383                 : 
    2384               0 :         psDefn->nParms = 7;
    2385               0 :         break;
    2386                 : 
    2387                 : /* -------------------------------------------------------------------- */
    2388                 :       case CT_AlbersEqualArea:
    2389                 :       case CT_EquidistantConic:
    2390                 : /* -------------------------------------------------------------------- */
    2391               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
    2392                 :                                 &dfStdParallel1 ) == 0 )
    2393               0 :             dfStdParallel1 = 0.0;
    2394                 : 
    2395               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
    2396                 :                                 &dfStdParallel2 ) == 0 )
    2397               0 :             dfStdParallel1 = 0.0;
    2398                 : 
    2399               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
    2400                 :                                 &dfNatOriginLong ) == 0
    2401                 :             && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
    2402                 :                                    &dfNatOriginLong ) == 0
    2403                 :             && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey", 
    2404                 :                                    &dfNatOriginLong ) == 0 )
    2405               0 :             dfNatOriginLong = 0.0;
    2406                 : 
    2407               0 :         if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
    2408                 :                                 &dfNatOriginLat ) == 0
    2409                 :             && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
    2410                 :                                    &dfNatOriginLat ) == 0
    2411                 :             && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
    2412                 :                                    &dfNatOriginLat ) == 0 )
    2413               0 :             dfNatOriginLat = 0.0;
    2414                 : 
    2415                 :         /* notdef: should transform to decimal degrees at this point */
    2416                 : 
    2417               0 :         psDefn->ProjParm[0] = dfStdParallel1;
    2418               0 :         psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
    2419               0 :         psDefn->ProjParm[1] = dfStdParallel2;
    2420               0 :         psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
    2421               0 :         psDefn->ProjParm[2] = dfNatOriginLat;
    2422               0 :         psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
    2423               0 :         psDefn->ProjParm[3] = dfNatOriginLong;
    2424               0 :         psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
    2425               0 :         psDefn->ProjParm[5] = dfFalseEasting;
    2426               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2427               0 :         psDefn->ProjParm[6] = dfFalseNorthing;
    2428               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2429                 : 
    2430               0 :         psDefn->nParms = 7;
    2431                 :         break;
    2432                 :     }
    2433               7 : }
    2434                 : 
    2435                 : /************************************************************************/
    2436                 : /*                            GetGTIFDefn()                             */
    2437                 : /*      This function borrowed from the GTIFGetDefn() function.         */
    2438                 : /*      See geo_normalize.c from the GeoTIFF package.                   */
    2439                 : /************************************************************************/
    2440                 : 
    2441              24 : void MrSIDDataset::GetGTIFDefn()
    2442                 : {
    2443                 :     double      dfInvFlattening;
    2444                 : 
    2445                 : /* -------------------------------------------------------------------- */
    2446                 : /*      Initially we default all the information we can.                */
    2447                 : /* -------------------------------------------------------------------- */
    2448              24 :     psDefn = new( GTIFDefn );
    2449              24 :     psDefn->Model = KvUserDefined;
    2450              24 :     psDefn->PCS = KvUserDefined;
    2451              24 :     psDefn->GCS = KvUserDefined;
    2452              24 :     psDefn->UOMLength = KvUserDefined;
    2453              24 :     psDefn->UOMLengthInMeters = 1.0;
    2454              24 :     psDefn->UOMAngle = KvUserDefined;
    2455              24 :     psDefn->UOMAngleInDegrees = 1.0;
    2456              24 :     psDefn->Datum = KvUserDefined;
    2457              24 :     psDefn->Ellipsoid = KvUserDefined;
    2458              24 :     psDefn->SemiMajor = 0.0;
    2459              24 :     psDefn->SemiMinor = 0.0;
    2460              24 :     psDefn->PM = KvUserDefined;
    2461              24 :     psDefn->PMLongToGreenwich = 0.0;
    2462                 : 
    2463              24 :     psDefn->ProjCode = KvUserDefined;
    2464              24 :     psDefn->Projection = KvUserDefined;
    2465              24 :     psDefn->CTProjection = KvUserDefined;
    2466                 : 
    2467              24 :     psDefn->nParms = 0;
    2468             264 :     for( int i = 0; i < MAX_GTIF_PROJPARMS; i++ )
    2469                 :     {
    2470             240 :         psDefn->ProjParm[i] = 0.0;
    2471             240 :         psDefn->ProjParmId[i] = 0;
    2472                 :     }
    2473                 : 
    2474              24 :     psDefn->MapSys = KvUserDefined;
    2475              24 :     psDefn->Zone = 0;
    2476                 : 
    2477                 : /* -------------------------------------------------------------------- */
    2478                 : /*      Try to get the overall model type.                              */
    2479                 : /* -------------------------------------------------------------------- */
    2480                 :     GetMetadataElement( "GEOTIFF_NUM::1024::GTModelTypeGeoKey",
    2481              24 :                         &(psDefn->Model) );
    2482                 : 
    2483                 : /* -------------------------------------------------------------------- */
    2484                 : /*      Try to get a PCS.                                               */
    2485                 : /* -------------------------------------------------------------------- */
    2486              24 :     if( GetMetadataElement( "GEOTIFF_NUM::3072::ProjectedCSTypeGeoKey",
    2487                 :                             &(psDefn->PCS) )
    2488                 :         && psDefn->PCS != KvUserDefined )
    2489                 :     {
    2490                 :         /*
    2491                 :          * Translate this into useful information.
    2492                 :          */
    2493                 :         GTIFGetPCSInfo( psDefn->PCS, NULL, &(psDefn->ProjCode),
    2494               4 :                         &(psDefn->UOMLength), &(psDefn->GCS) );
    2495                 :     }
    2496                 : 
    2497                 : /* -------------------------------------------------------------------- */
    2498                 : /*       If we have the PCS code, but didn't find it in the CSV files   */
    2499                 : /*      (likely because we can't find them) we will try some ``jiffy    */
    2500                 : /*      rules'' for UTM and state plane.                                */
    2501                 : /* -------------------------------------------------------------------- */
    2502              24 :     if( psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined )
    2503                 :     {
    2504                 :         int     nMapSys, nZone;
    2505               0 :         int     nGCS = psDefn->GCS;
    2506                 : 
    2507               0 :         nMapSys = GTIFPCSToMapSys( psDefn->PCS, &nGCS, &nZone );
    2508               0 :         if( nMapSys != KvUserDefined )
    2509                 :         {
    2510               0 :             psDefn->ProjCode = (short) GTIFMapSysToProj( nMapSys, nZone );
    2511               0 :             psDefn->GCS = (short) nGCS;
    2512                 :         }
    2513                 :     }
    2514                 :    
    2515                 : /* -------------------------------------------------------------------- */
    2516                 : /*      If the Proj_ code is specified directly, use that.              */
    2517                 : /* -------------------------------------------------------------------- */
    2518              24 :     if( psDefn->ProjCode == KvUserDefined )
    2519                 :         GetMetadataElement( "GEOTIFF_NUM::3074::ProjectionGeoKey",
    2520              20 :                             &(psDefn->ProjCode) );
    2521                 :     
    2522              24 :     if( psDefn->ProjCode != KvUserDefined )
    2523                 :     {
    2524                 :         /*
    2525                 :          * We have an underlying projection transformation value.  Look
    2526                 :          * this up.  For a PCS of ``WGS 84 / UTM 11'' the transformation
    2527                 :          * would be Transverse Mercator, with a particular set of options.
    2528                 :          * The nProjTRFCode itself would correspond to the name
    2529                 :          * ``UTM zone 11N'', and doesn't include datum info.
    2530                 :          */
    2531                 :         GTIFGetProjTRFInfo( psDefn->ProjCode, NULL, &(psDefn->Projection),
    2532               4 :                             psDefn->ProjParm );
    2533                 :         
    2534                 :         /*
    2535                 :          * Set the GeoTIFF identity of the parameters.
    2536                 :          */
    2537                 :         psDefn->CTProjection = (short)
    2538               4 :             EPSGProjMethodToCTProjMethod( psDefn->Projection );
    2539                 : 
    2540               4 :         SetGTParmIds( psDefn->CTProjection, psDefn->ProjParmId, NULL);
    2541               4 :         psDefn->nParms = 7;
    2542                 :     }
    2543                 : 
    2544                 : /* -------------------------------------------------------------------- */
    2545                 : /*      Try to get a GCS.  If found, it will override any implied by    */
    2546                 : /*      the PCS.                                                        */
    2547                 : /* -------------------------------------------------------------------- */
    2548                 :     GetMetadataElement( "GEOTIFF_NUM::2048::GeographicTypeGeoKey",
    2549              24 :                         &(psDefn->GCS) );
    2550                 : 
    2551                 : /* -------------------------------------------------------------------- */
    2552                 : /*      Derive the datum, and prime meridian from the GCS.              */
    2553                 : /* -------------------------------------------------------------------- */
    2554              24 :     if( psDefn->GCS != KvUserDefined )
    2555                 :     {
    2556                 :         GTIFGetGCSInfo( psDefn->GCS, NULL, &(psDefn->Datum), &(psDefn->PM),
    2557              13 :                         &(psDefn->UOMAngle) );
    2558                 :     }
    2559                 :     
    2560                 : /* -------------------------------------------------------------------- */
    2561                 : /*      Handle the GCS angular units.  GeogAngularUnitsGeoKey           */
    2562                 : /*      overrides the GCS or PCS setting.                               */
    2563                 : /* -------------------------------------------------------------------- */
    2564                 :     GetMetadataElement( "GEOTIFF_NUM::2054::GeogAngularUnitsGeoKey",
    2565              24 :                         &(psDefn->UOMAngle) );
    2566              24 :     if( psDefn->UOMAngle != KvUserDefined )
    2567                 :     {
    2568                 :         GTIFGetUOMAngleInfo( psDefn->UOMAngle, NULL,
    2569              13 :                              &(psDefn->UOMAngleInDegrees) );
    2570                 :     }
    2571                 : 
    2572                 : /* -------------------------------------------------------------------- */
    2573                 : /*      Check for a datum setting, and then use the datum to derive     */
    2574                 : /*      an ellipsoid.                                                   */
    2575                 : /* -------------------------------------------------------------------- */
    2576                 :     GetMetadataElement( "GEOTIFF_NUM::2050::GeogGeodeticDatumGeoKey",
    2577              24 :                         &(psDefn->Datum) );
    2578                 : 
    2579              24 :     if( psDefn->Datum != KvUserDefined )
    2580                 :     {
    2581              13 :         GTIFGetDatumInfo( psDefn->Datum, NULL, &(psDefn->Ellipsoid) );
    2582                 :     }
    2583                 : 
    2584                 : /* -------------------------------------------------------------------- */
    2585                 : /*      Check for an explicit ellipsoid.  Use the ellipsoid to          */
    2586                 : /*      derive the ellipsoid characteristics, if possible.              */
    2587                 : /* -------------------------------------------------------------------- */
    2588                 :     GetMetadataElement( "GEOTIFF_NUM::2056::GeogEllipsoidGeoKey",
    2589              24 :                         &(psDefn->Ellipsoid) );
    2590                 : 
    2591              24 :     if( psDefn->Ellipsoid != KvUserDefined )
    2592                 :     {
    2593                 :         GTIFGetEllipsoidInfo( psDefn->Ellipsoid, NULL,
    2594              13 :                               &(psDefn->SemiMajor), &(psDefn->SemiMinor) );
    2595                 :     }
    2596                 : 
    2597                 : /* -------------------------------------------------------------------- */
    2598                 : /*      Check for overridden ellipsoid parameters.  It would be nice    */
    2599                 : /*      to warn if they conflict with provided information, but for     */
    2600                 : /*      now we just override.                                           */
    2601                 : /* -------------------------------------------------------------------- */
    2602                 :     GetMetadataElement( "GEOTIFF_NUM::2057::GeogSemiMajorAxisGeoKey",
    2603              24 :                         &(psDefn->SemiMajor) );
    2604                 :     GetMetadataElement( "GEOTIFF_NUM::2058::GeogSemiMinorAxisGeoKey",
    2605              24 :                         &(psDefn->SemiMinor) );
    2606                 :     
    2607              24 :     if( GetMetadataElement( "GEOTIFF_NUM::2059::GeogInvFlatteningGeoKey",
    2608                 :                             &dfInvFlattening ) == 1 )
    2609                 :     {
    2610               0 :         if( dfInvFlattening != 0.0 )
    2611                 :             psDefn->SemiMinor = 
    2612               0 :                 psDefn->SemiMajor * (1 - 1.0/dfInvFlattening);
    2613                 :     }
    2614                 : 
    2615                 : /* -------------------------------------------------------------------- */
    2616                 : /*      Get the prime meridian info.                                    */
    2617                 : /* -------------------------------------------------------------------- */
    2618                 :     GetMetadataElement( "GEOTIFF_NUM::2051::GeogPrimeMeridianGeoKey",
    2619              24 :                         &(psDefn->PM) );
    2620                 : 
    2621              24 :     if( psDefn->PM != KvUserDefined )
    2622                 :     {
    2623              13 :         GTIFGetPMInfo( psDefn->PM, NULL, &(psDefn->PMLongToGreenwich) );
    2624                 :     }
    2625                 :     else
    2626                 :     {
    2627                 :         GetMetadataElement( "GEOTIFF_NUM::2061::GeogPrimeMeridianLongGeoKey",
    2628              11 :                             &(psDefn->PMLongToGreenwich) );
    2629                 : 
    2630                 :         psDefn->PMLongToGreenwich =
    2631                 :             GTIFAngleToDD( psDefn->PMLongToGreenwich,
    2632              11 :                            psDefn->UOMAngle );
    2633                 :     }
    2634                 : 
    2635                 : /* -------------------------------------------------------------------- */
    2636                 : /*      Have the projection units of measure been overridden?  We       */
    2637                 : /*      should likely be doing something about angular units too,       */
    2638                 : /*      but these are very rarely not decimal degrees for actual        */
    2639                 : /*      file coordinates.                                               */
    2640                 : /* -------------------------------------------------------------------- */
    2641                 :     GetMetadataElement( "GEOTIFF_NUM::3076::ProjLinearUnitsGeoKey",
    2642              24 :                         &(psDefn->UOMLength) );
    2643                 : 
    2644              24 :     if( psDefn->UOMLength != KvUserDefined )
    2645                 :     {
    2646                 :         GTIFGetUOMLengthInfo( psDefn->UOMLength, NULL,
    2647              11 :                               &(psDefn->UOMLengthInMeters) );
    2648                 :     }
    2649                 : 
    2650                 : /* -------------------------------------------------------------------- */
    2651                 : /*      Handle a variety of user defined transform types.               */
    2652                 : /* -------------------------------------------------------------------- */
    2653              24 :     if( GetMetadataElement( "GEOTIFF_NUM::3075::ProjCoordTransGeoKey",
    2654                 :                             &(psDefn->CTProjection) ) )
    2655                 :     {
    2656               7 :         FetchProjParms();
    2657                 :     }
    2658                 : 
    2659                 : /* -------------------------------------------------------------------- */
    2660                 : /*      Try to set the zoned map system information.                    */
    2661                 : /* -------------------------------------------------------------------- */
    2662              24 :     psDefn->MapSys = GTIFProjToMapSys( psDefn->ProjCode, &(psDefn->Zone) );
    2663                 : 
    2664                 : /* -------------------------------------------------------------------- */
    2665                 : /*      If this is UTM, and we were unable to extract the projection    */
    2666                 : /*      parameters from the CSV file, just set them directly now,       */
    2667                 : /*      since it's pretty easy, and a common case.                      */
    2668                 : /* -------------------------------------------------------------------- */
    2669              24 :     if( (psDefn->MapSys == MapSys_UTM_North
    2670                 :          || psDefn->MapSys == MapSys_UTM_South)
    2671                 :         && psDefn->CTProjection == KvUserDefined )
    2672                 :     {
    2673               0 :         psDefn->CTProjection = CT_TransverseMercator;
    2674               0 :         psDefn->nParms = 7;
    2675               0 :         psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
    2676               0 :         psDefn->ProjParm[0] = 0.0;
    2677                 :             
    2678               0 :         psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
    2679               0 :         psDefn->ProjParm[1] = psDefn->Zone*6 - 183.0;
    2680                 :         
    2681               0 :         psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
    2682               0 :         psDefn->ProjParm[4] = 0.9996;
    2683                 :         
    2684               0 :         psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
    2685               0 :         psDefn->ProjParm[5] = 500000.0;
    2686                 :         
    2687               0 :         psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
    2688                 : 
    2689               0 :         if( psDefn->MapSys == MapSys_UTM_North )
    2690               0 :             psDefn->ProjParm[6] = 0.0;
    2691                 :         else
    2692               0 :             psDefn->ProjParm[6] = 10000000.0;
    2693                 :     }
    2694                 : 
    2695              24 :     if ( pszProjection )
    2696              24 :         CPLFree( pszProjection );
    2697              24 :     pszProjection = GetOGISDefn( psDefn );
    2698              24 : }
    2699                 : 
    2700                 : 
    2701                 : /************************************************************************/
    2702                 : /*                       GTIFToCPLRecyleString()                        */
    2703                 : /*                                                                      */
    2704                 : /*      This changes a string from the libgeotiff heap to the GDAL      */
    2705                 : /*      heap.                                                           */
    2706                 : /************************************************************************/
    2707                 : 
    2708              64 : static void GTIFToCPLRecycleString( char **ppszTarget )
    2709                 : 
    2710                 : {
    2711              64 :     if( *ppszTarget == NULL )
    2712               0 :         return;
    2713                 : 
    2714              64 :     char *pszTempString = CPLStrdup(*ppszTarget);
    2715              64 :     GTIFFreeMemory( *ppszTarget );
    2716              64 :     *ppszTarget = pszTempString;
    2717                 : }
    2718                 : 
    2719                 : /************************************************************************/
    2720                 : /*                          GetOGISDefn()                               */
    2721                 : /*  Copied from the gt_wkt_srs.cpp.                                     */
    2722                 : /************************************************************************/
    2723                 : 
    2724              24 : char *MrSIDDataset::GetOGISDefn( GTIFDefn *psDefn )
    2725                 : {
    2726              24 :     OGRSpatialReference oSRS;
    2727                 : 
    2728              24 :     if( psDefn->Model != ModelTypeProjected 
    2729                 :         && psDefn->Model != ModelTypeGeographic )
    2730              11 :         return CPLStrdup("");
    2731                 :     
    2732                 : /* -------------------------------------------------------------------- */
    2733                 : /*      If this is a projected SRS we set the PROJCS keyword first      */
    2734                 : /*      to ensure that the GEOGCS will be a child.                      */
    2735                 : /* -------------------------------------------------------------------- */
    2736              13 :     if( psDefn->Model == ModelTypeProjected )
    2737                 :     {
    2738                 :         char    *pszPCSName;
    2739              11 :         int     bPCSNameSet = FALSE;
    2740                 : 
    2741              11 :         if( psDefn->PCS != KvUserDefined )
    2742                 :         {
    2743                 : 
    2744               4 :             if( GTIFGetPCSInfo( psDefn->PCS, &pszPCSName, NULL, NULL, NULL ) )
    2745               4 :                 bPCSNameSet = TRUE;
    2746                 :             
    2747               4 :             oSRS.SetNode( "PROJCS", bPCSNameSet ? pszPCSName : "unnamed" );
    2748               4 :             if( bPCSNameSet )
    2749               4 :                 GTIFFreeMemory( pszPCSName );
    2750                 : 
    2751               4 :             oSRS.SetAuthority( "PROJCS", "EPSG", psDefn->PCS );
    2752                 :         }
    2753                 :         else
    2754                 :         {
    2755                 :             char szPCSName[200];
    2756               7 :             strcpy( szPCSName, "unnamed" );
    2757               7 :             if ( GetMetadataElement( "GEOTIFF_NUM::1026::GTCitationGeoKey",
    2758                 :                                      szPCSName, sizeof(szPCSName) ) )
    2759               7 :                 oSRS.SetNode( "PROJCS", szPCSName );
    2760                 :         }
    2761                 :     }
    2762                 :     
    2763                 : /* ==================================================================== */
    2764                 : /*      Setup the GeogCS                                                */
    2765                 : /* ==================================================================== */
    2766              13 :     char        *pszGeogName = NULL;
    2767              13 :     char        *pszDatumName = NULL;
    2768              13 :     char        *pszPMName = NULL;
    2769              13 :     char        *pszSpheroidName = NULL;
    2770              13 :     char        *pszAngularUnits = NULL;
    2771                 :     double      dfInvFlattening, dfSemiMajor;
    2772                 :     char        szGCSName[200];
    2773                 :     
    2774              13 :     if( GetMetadataElement( "GEOTIFF_NUM::2049::GeogCitationGeoKey",
    2775                 :                             szGCSName, sizeof(szGCSName) ) )
    2776               1 :         pszGeogName = CPLStrdup(szGCSName);
    2777                 :     else
    2778                 :     {
    2779              12 :         GTIFGetGCSInfo( psDefn->GCS, &pszGeogName, NULL, NULL, NULL );
    2780              12 :         GTIFToCPLRecycleString(&pszGeogName);
    2781                 :     }
    2782              13 :     GTIFGetDatumInfo( psDefn->Datum, &pszDatumName, NULL );
    2783              13 :     GTIFToCPLRecycleString(&pszDatumName);
    2784              13 :     GTIFGetPMInfo( psDefn->PM, &pszPMName, NULL );
    2785              13 :     GTIFToCPLRecycleString(&pszPMName);
    2786              13 :     GTIFGetEllipsoidInfo( psDefn->Ellipsoid, &pszSpheroidName, NULL, NULL );
    2787              13 :     GTIFToCPLRecycleString(&pszSpheroidName);
    2788                 :     
    2789              13 :     GTIFGetUOMAngleInfo( psDefn->UOMAngle, &pszAngularUnits, NULL );
    2790              13 :     GTIFToCPLRecycleString(&pszAngularUnits);
    2791              13 :     if( pszAngularUnits == NULL )
    2792               0 :         pszAngularUnits = CPLStrdup("unknown");
    2793                 : 
    2794              13 :     if( pszDatumName != NULL )
    2795              13 :         WKTMassageDatum( &pszDatumName );
    2796                 : 
    2797              13 :     dfSemiMajor = psDefn->SemiMajor;
    2798              13 :     if( psDefn->SemiMajor == 0.0 )
    2799                 :     {
    2800               0 :         pszSpheroidName = CPLStrdup("unretrievable - using WGS84");
    2801               0 :         dfSemiMajor = SRS_WGS84_SEMIMAJOR;
    2802               0 :         dfInvFlattening = SRS_WGS84_INVFLATTENING;
    2803                 :     }
    2804              26 :     else if( (psDefn->SemiMinor / psDefn->SemiMajor) < 0.99999999999999999
    2805                 :              || (psDefn->SemiMinor / psDefn->SemiMajor) > 1.00000000000000001 )
    2806              13 :         dfInvFlattening = -1.0 / (psDefn->SemiMinor/psDefn->SemiMajor - 1.0);
    2807                 :     else
    2808               0 :         dfInvFlattening = 0.0; /* special flag for infinity */
    2809                 : 
    2810                 :     oSRS.SetGeogCS( pszGeogName, pszDatumName, 
    2811                 :                     pszSpheroidName, dfSemiMajor, dfInvFlattening,
    2812                 :                     pszPMName,
    2813                 :                     psDefn->PMLongToGreenwich / psDefn->UOMAngleInDegrees,
    2814                 :                     pszAngularUnits,
    2815              13 :                     psDefn->UOMAngleInDegrees * 0.0174532925199433 );
    2816                 : 
    2817              13 :     if( psDefn->GCS != KvUserDefined )
    2818              13 :         oSRS.SetAuthority( "GEOGCS", "EPSG", psDefn->GCS );
    2819                 : 
    2820              13 :     if( psDefn->Datum != KvUserDefined )
    2821              13 :         oSRS.SetAuthority( "DATUM", "EPSG", psDefn->Datum );
    2822                 : 
    2823              13 :     if( psDefn->Ellipsoid != KvUserDefined )
    2824              13 :         oSRS.SetAuthority( "SPHEROID", "EPSG", psDefn->Ellipsoid );
    2825                 : 
    2826              13 :     CPLFree( pszGeogName );
    2827              13 :     CPLFree( pszDatumName );
    2828              13 :     CPLFree( pszPMName );
    2829              13 :     CPLFree( pszSpheroidName );
    2830              13 :     CPLFree( pszAngularUnits );
    2831                 :         
    2832                 : /* ==================================================================== */
    2833                 : /*      Handle projection parameters.                                   */
    2834                 : /* ==================================================================== */
    2835              13 :     if( psDefn->Model == ModelTypeProjected )
    2836                 :     {
    2837                 : /* -------------------------------------------------------------------- */
    2838                 : /*      Make a local copy of parms, and convert back into the           */
    2839                 : /*      angular units of the GEOGCS and the linear units of the         */
    2840                 : /*      projection.                                                     */
    2841                 : /* -------------------------------------------------------------------- */
    2842                 :         double          adfParm[10];
    2843                 :         int             i;
    2844                 : 
    2845              88 :         for( i = 0; i < MIN(10,psDefn->nParms); i++ )
    2846              77 :             adfParm[i] = psDefn->ProjParm[i];
    2847                 : 
    2848              11 :         adfParm[0] /= psDefn->UOMAngleInDegrees;
    2849              11 :         adfParm[1] /= psDefn->UOMAngleInDegrees;
    2850              11 :         adfParm[2] /= psDefn->UOMAngleInDegrees;
    2851              11 :         adfParm[3] /= psDefn->UOMAngleInDegrees;
    2852                 :         
    2853              11 :         adfParm[5] /= psDefn->UOMLengthInMeters;
    2854              11 :         adfParm[6] /= psDefn->UOMLengthInMeters;
    2855                 :         
    2856                 : /* -------------------------------------------------------------------- */
    2857                 : /*      Translation the fundamental projection.                         */
    2858                 : /* -------------------------------------------------------------------- */
    2859              11 :         switch( psDefn->CTProjection )
    2860                 :         {
    2861                 :           case CT_TransverseMercator:
    2862                 :             oSRS.SetTM( adfParm[0], adfParm[1],
    2863                 :                         adfParm[4],
    2864               4 :                         adfParm[5], adfParm[6] );
    2865               4 :             break;
    2866                 : 
    2867                 :           case CT_TransvMercator_SouthOriented:
    2868                 :             oSRS.SetTMSO( adfParm[0], adfParm[1],
    2869                 :                           adfParm[4],
    2870               0 :                           adfParm[5], adfParm[6] );
    2871               0 :             break;
    2872                 : 
    2873                 :           case CT_Mercator:
    2874                 :             oSRS.SetMercator( adfParm[0], adfParm[1],
    2875                 :                               adfParm[4],
    2876               7 :                               adfParm[5], adfParm[6] );
    2877               7 :             break;
    2878                 : 
    2879                 :           case CT_ObliqueStereographic:
    2880                 :             oSRS.SetOS( adfParm[0], adfParm[1],
    2881                 :                         adfParm[4],
    2882               0 :                         adfParm[5], adfParm[6] );
    2883               0 :             break;
    2884                 : 
    2885                 :           case CT_Stereographic:
    2886                 :             oSRS.SetOS( adfParm[0], adfParm[1],
    2887                 :                         adfParm[4],
    2888               0 :                         adfParm[5], adfParm[6] );
    2889               0 :             break;
    2890                 : 
    2891                 :           case CT_ObliqueMercator: /* hotine */
    2892                 :             oSRS.SetHOM( adfParm[0], adfParm[1],
    2893                 :                          adfParm[2], adfParm[3],
    2894                 :                          adfParm[4],
    2895               0 :                          adfParm[5], adfParm[6] );
    2896               0 :             break;
    2897                 :         
    2898                 :           case CT_EquidistantConic: 
    2899                 :             oSRS.SetEC( adfParm[0], adfParm[1],
    2900                 :                         adfParm[2], adfParm[3],
    2901               0 :                         adfParm[5], adfParm[6] );
    2902               0 :             break;
    2903                 :         
    2904                 :           case CT_CassiniSoldner:
    2905                 :             oSRS.SetCS( adfParm[0], adfParm[1],
    2906               0 :                         adfParm[5], adfParm[6] );
    2907               0 :             break;
    2908                 :         
    2909                 :           case CT_Polyconic:
    2910                 :             oSRS.SetPolyconic( adfParm[0], adfParm[1],
    2911               0 :                                adfParm[5], adfParm[6] );
    2912               0 :             break;
    2913                 : 
    2914                 :           case CT_AzimuthalEquidistant:
    2915                 :             oSRS.SetAE( adfParm[0], adfParm[1],
    2916               0 :                         adfParm[5], adfParm[6] );
    2917               0 :             break;
    2918                 :         
    2919                 :           case CT_MillerCylindrical:
    2920                 :             oSRS.SetMC( adfParm[0], adfParm[1],
    2921               0 :                         adfParm[5], adfParm[6] );
    2922               0 :             break;
    2923                 :         
    2924                 :           case CT_Equirectangular:
    2925                 :             oSRS.SetEquirectangular( adfParm[0], adfParm[1],
    2926               0 :                                      adfParm[5], adfParm[6] );
    2927               0 :             break;
    2928                 :         
    2929                 :           case CT_Gnomonic:
    2930                 :             oSRS.SetGnomonic( adfParm[0], adfParm[1],
    2931               0 :                               adfParm[5], adfParm[6] );
    2932               0 :             break;
    2933                 :         
    2934                 :           case CT_LambertAzimEqualArea:
    2935                 :             oSRS.SetLAEA( adfParm[0], adfParm[1],
    2936               0 :                           adfParm[5], adfParm[6] );
    2937               0 :             break;
    2938                 :         
    2939                 :           case CT_Orthographic:
    2940                 :             oSRS.SetOrthographic( adfParm[0], adfParm[1],
    2941               0 :                                   adfParm[5], adfParm[6] );
    2942               0 :             break;
    2943                 :         
    2944                 :           case CT_Robinson:
    2945                 :             oSRS.SetRobinson( adfParm[1],
    2946               0 :                               adfParm[5], adfParm[6] );
    2947               0 :             break;
    2948                 :         
    2949                 :           case CT_Sinusoidal:
    2950                 :             oSRS.SetSinusoidal( adfParm[1],
    2951               0 :                                 adfParm[5], adfParm[6] );
    2952               0 :             break;
    2953                 :         
    2954                 :           case CT_VanDerGrinten:
    2955                 :             oSRS.SetVDG( adfParm[1],
    2956               0 :                          adfParm[5], adfParm[6] );
    2957               0 :             break;
    2958                 : 
    2959                 :           case CT_PolarStereographic:
    2960                 :             oSRS.SetPS( adfParm[0], adfParm[1],
    2961                 :                         adfParm[4],
    2962               0 :                         adfParm[5], adfParm[6] );
    2963               0 :             break;
    2964                 :         
    2965                 :           case CT_LambertConfConic_2SP:
    2966                 :             oSRS.SetLCC( adfParm[2], adfParm[3],
    2967                 :                          adfParm[0], adfParm[1],
    2968               0 :                          adfParm[5], adfParm[6] );
    2969               0 :             break;
    2970                 : 
    2971                 :           case CT_LambertConfConic_1SP:
    2972                 :             oSRS.SetLCC1SP( adfParm[0], adfParm[1],
    2973                 :                             adfParm[4],
    2974               0 :                             adfParm[5], adfParm[6] );
    2975               0 :             break;
    2976                 :         
    2977                 :           case CT_AlbersEqualArea:
    2978                 :             oSRS.SetACEA( adfParm[0], adfParm[1],
    2979                 :                           adfParm[2], adfParm[3],
    2980               0 :                           adfParm[5], adfParm[6] );
    2981               0 :             break;
    2982                 : 
    2983                 :           case CT_NewZealandMapGrid:
    2984                 :             oSRS.SetNZMG( adfParm[0], adfParm[1],
    2985               0 :                           adfParm[5], adfParm[6] );
    2986                 :             break;
    2987                 :         }
    2988                 : 
    2989                 : /* -------------------------------------------------------------------- */
    2990                 : /*      Set projection units.                                           */
    2991                 : /* -------------------------------------------------------------------- */
    2992              11 :         char    *pszUnitsName = NULL;
    2993                 :         
    2994              11 :         GTIFGetUOMLengthInfo( psDefn->UOMLength, &pszUnitsName, NULL );
    2995                 : 
    2996              22 :         if( pszUnitsName != NULL && psDefn->UOMLength != KvUserDefined )
    2997                 :         {
    2998              11 :             oSRS.SetLinearUnits( pszUnitsName, psDefn->UOMLengthInMeters );
    2999              11 :             oSRS.SetAuthority( "PROJCS|UNIT", "EPSG", psDefn->UOMLength );
    3000                 :         }
    3001                 :         else
    3002               0 :             oSRS.SetLinearUnits( "unknown", psDefn->UOMLengthInMeters );
    3003                 : 
    3004              11 :         GTIFFreeMemory( pszUnitsName );
    3005                 :     }
    3006                 :     
    3007                 : /* -------------------------------------------------------------------- */
    3008                 : /*      Return the WKT serialization of the object.                     */
    3009                 : /* -------------------------------------------------------------------- */
    3010                 :     char        *pszWKT;
    3011                 : 
    3012              13 :     oSRS.FixupOrdering();
    3013                 : 
    3014              13 :     if( oSRS.exportToWkt( &pszWKT ) == OGRERR_NONE )
    3015              13 :         return pszWKT;
    3016                 :     else
    3017               0 :         return NULL;
    3018                 : }
    3019                 : 
    3020                 : #ifdef MRSID_ESDK
    3021                 : 
    3022                 : /************************************************************************/
    3023                 : /* ==================================================================== */
    3024                 : /*                        MrSIDDummyImageReader                         */
    3025                 : /*                                                                      */
    3026                 : /*  This is a helper class to wrap GDAL calls in MrSID interface.       */
    3027                 : /* ==================================================================== */
    3028                 : /************************************************************************/
    3029                 : 
    3030                 : class MrSIDDummyImageReader : public LTIImageReader
    3031                 : {
    3032                 :   public:
    3033                 : 
    3034                 :     MrSIDDummyImageReader( GDALDataset *poSrcDS );
    3035                 :     ~MrSIDDummyImageReader();
    3036                 :     LT_STATUS           initialize();
    3037                 :     lt_int64            getPhysicalFileSize(void) const { return 0; };
    3038                 : 
    3039                 :   private:
    3040                 :     GDALDataset         *poDS;
    3041                 :     GDALDataType        eDataType;
    3042                 :     LTIDataType         eSampleType;
    3043                 :     const LTIPixel      *poPixel;
    3044                 :     
    3045                 :     double              adfGeoTransform[6];
    3046                 : 
    3047                 :     virtual LT_STATUS   decodeStrip( LTISceneBuffer& stripBuffer,
    3048                 :                                      const LTIScene& stripScene );
    3049                 :     virtual LT_STATUS   decodeBegin( const LTIScene& )
    3050                 :                             { return LT_STS_Success; };
    3051                 :     virtual LT_STATUS   decodeEnd() { return LT_STS_Success; };
    3052                 : };
    3053                 : 
    3054                 : /************************************************************************/
    3055                 : /*                        MrSIDDummyImageReader()                       */
    3056                 : /************************************************************************/
    3057                 : 
    3058                 : MrSIDDummyImageReader::MrSIDDummyImageReader( GDALDataset *poSrcDS ) :
    3059                 :                                             LTIImageReader(), poDS(poSrcDS)
    3060                 : {
    3061                 :     poPixel = NULL;
    3062                 : }
    3063                 : 
    3064                 : /************************************************************************/
    3065                 : /*                        ~MrSIDDummyImageReader()                      */
    3066                 : /************************************************************************/
    3067                 : 
    3068                 : MrSIDDummyImageReader::~MrSIDDummyImageReader()
    3069                 : {
    3070                 :     if ( poPixel )
    3071                 :         delete poPixel;
    3072                 : }
    3073                 : 
    3074                 : /************************************************************************/
    3075                 : /*                             initialize()                             */
    3076                 : /************************************************************************/
    3077                 : 
    3078                 : LT_STATUS MrSIDDummyImageReader::initialize()
    3079                 : {
    3080                 :     LT_STATUS eStat = LT_STS_Uninit;
    3081                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
    3082                 :     if ( !LT_SUCCESS(eStat = LTIImageReader::init()) )
    3083                 :         return eStat;
    3084                 : #else
    3085                 :     if ( !LT_SUCCESS(eStat = LTIImageReader::initialize()) )
    3086                 :         return eStat;
    3087                 : #endif
    3088                 :     
    3089                 :     lt_uint16 nBands = (lt_uint16)poDS->GetRasterCount();
    3090                 :     LTIColorSpace eColorSpace = LTI_COLORSPACE_RGB;
    3091                 :     switch ( nBands )
    3092                 :     {
    3093                 :         case 1:
    3094                 :             eColorSpace = LTI_COLORSPACE_GRAYSCALE;
    3095                 :             break;
    3096                 :         case 3:
    3097                 :             eColorSpace = LTI_COLORSPACE_RGB;
    3098                 :             break;
    3099                 :         default:
    3100                 :             eColorSpace = LTI_COLORSPACE_MULTISPECTRAL;
    3101                 :             break;
    3102                 :     }
    3103                 :     
    3104                 :     eDataType = poDS->GetRasterBand(1)->GetRasterDataType();
    3105                 :     switch ( eDataType )
    3106                 :     {
    3107                 :         case GDT_UInt16:
    3108                 :             eSampleType = LTI_DATATYPE_UINT16;
    3109                 :             break;
    3110                 :         case GDT_Int16:
    3111                 :             eSampleType = LTI_DATATYPE_SINT16;
    3112                 :             break;
    3113                 :         case GDT_UInt32:
    3114                 :             eSampleType = LTI_DATATYPE_UINT32;
    3115                 :             break;
    3116                 :         case GDT_Int32:
    3117                 :             eSampleType = LTI_DATATYPE_SINT32;
    3118                 :             break;
    3119                 :         case GDT_Float32:
    3120                 :             eSampleType = LTI_DATATYPE_FLOAT32;
    3121                 :             break;
    3122                 :         case GDT_Float64:
    3123                 :             eSampleType = LTI_DATATYPE_FLOAT64;
    3124                 :             break;
    3125                 :         case GDT_Byte:
    3126                 :         default:
    3127                 :             eSampleType = LTI_DATATYPE_UINT8;
    3128                 :             break;
    3129                 :     }
    3130                 : 
    3131                 :     poPixel = new LTIDLLPixel<LTIPixel>( eColorSpace, nBands, eSampleType );
    3132                 :     if ( !LT_SUCCESS(setPixelProps(*poPixel)) )
    3133                 :         return LT_STS_Failure;
    3134                 : 
    3135                 :     if ( !LT_SUCCESS(setDimensions(poDS->GetRasterXSize(),
    3136                 :                                    poDS->GetRasterYSize())) )
    3137                 :         return LT_STS_Failure;
    3138                 : 
    3139                 :     if ( poDS->GetGeoTransform( adfGeoTransform ) == CE_None )
    3140                 :     {
    3141                 : #ifdef MRSID_SDK_40
    3142                 :         LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
    3143                 :                           adfGeoTransform[3] + adfGeoTransform[5] / 2,
    3144                 :                           adfGeoTransform[1], adfGeoTransform[5],
    3145                 :                           adfGeoTransform[2], adfGeoTransform[4], NULL,
    3146                 :                           poDS->GetProjectionRef() );
    3147                 : #else
    3148                 :         LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
    3149                 :                           adfGeoTransform[3] + adfGeoTransform[5] / 2,
    3150                 :                           adfGeoTransform[1], adfGeoTransform[5],
    3151                 :                           adfGeoTransform[2], adfGeoTransform[4], 
    3152                 :                           poDS->GetProjectionRef() );
    3153                 : #endif
    3154                 :         if ( !LT_SUCCESS(setGeoCoord( oGeo )) )
    3155                 :             return LT_STS_Failure;
    3156                 :     }
    3157                 : 
    3158                 :     /*int     bSuccess;
    3159                 :     double  dfNoDataValue = poDS->GetNoDataValue( &bSuccess );
    3160                 :     if ( bSuccess )
    3161                 :     {
    3162                 :         LTIPixel    oNoDataPixel( *poPixel );
    3163                 :         lt_uint16   iBand;
    3164                 : 
    3165                 :         for (iBand = 0; iBand < (lt_uint16)poDS->GetRasterCount(); iBand++)
    3166                 :             oNoDataPixel.setSampleValueFloat32( iBand, dfNoDataValue );
    3167                 :         if ( !LT_SUCCESS(setNoDataPixel( &oNoDataPixel )) )
    3168                 :             return LT_STS_Failure;
    3169                 :     }*/
    3170                 : 
    3171                 :     setDefaultDynamicRange();
    3172                 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3173                 :     setClassicalMetadata();
    3174                 : #endif
    3175                 : 
    3176                 :     return LT_STS_Success;
    3177                 : }
    3178                 : 
    3179                 : /************************************************************************/
    3180                 : /*                             decodeStrip()                            */
    3181                 : /************************************************************************/
    3182                 : 
    3183                 : LT_STATUS MrSIDDummyImageReader::decodeStrip(LTISceneBuffer& stripData,
    3184                 :                                              const LTIScene& stripScene)
    3185                 : 
    3186                 : {
    3187                 :     const lt_int32  nXOff = stripScene.getUpperLeftCol();
    3188                 :     const lt_int32  nYOff = stripScene.getUpperLeftRow();
    3189                 :     const lt_int32  nBufXSize = stripScene.getNumCols();
    3190                 :     const lt_int32  nBufYSize = stripScene.getNumRows();
    3191                 :     const lt_int32  nDataBufXSize = stripData.getTotalNumCols();
    3192                 :     const lt_int32  nDataBufYSize = stripData.getTotalNumRows();
    3193                 :     const lt_uint16 nBands = poPixel->getNumBands();
    3194                 : 
    3195                 :     void *pData = CPLMalloc(nDataBufXSize * nDataBufYSize * poPixel->getNumBytes());
    3196                 :     if ( !pData )
    3197                 :     {
    3198                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3199                 :                   "MrSIDDummyImageReader::decodeStrip(): "
    3200                 :                   "Cannot allocate enough space for scene buffer" );
    3201                 :         return LT_STS_Failure;
    3202                 :     }
    3203                 : 
    3204                 :     poDS->RasterIO( GF_Read, nXOff, nYOff, nBufXSize, nBufYSize, 
    3205                 :                     pData, nBufXSize, nBufYSize, eDataType, nBands, NULL, 
    3206                 :                     0, 0, 0 );
    3207                 : 
    3208                 :     stripData.importDataBSQ( pData );
    3209                 :     CPLFree( pData );
    3210                 :     return LT_STS_Success;
    3211                 : }
    3212                 : 
    3213                 : /************************************************************************/
    3214                 : /*                             FlushCache()                             */
    3215                 : /************************************************************************/
    3216                 : 
    3217                 : void MrSIDDataset::FlushCache()
    3218                 : 
    3219                 : {
    3220                 :     GDALDataset::FlushCache();
    3221                 : }
    3222                 : 
    3223                 : /************************************************************************/
    3224                 : /*                          MrSIDCreateCopy()                           */
    3225                 : /************************************************************************/
    3226                 : 
    3227                 : static GDALDataset *
    3228                 : MrSIDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
    3229                 :                  int bStrict, char ** papszOptions, 
    3230                 :                  GDALProgressFunc pfnProgress, void * pProgressData )
    3231                 : 
    3232                 : { 
    3233                 :     const char* pszVersion = CSLFetchNameValue(papszOptions, "VERSION");
    3234                 : #ifdef MRSID_HAVE_MG4WRITE
    3235                 :     int iVersion = pszVersion ? atoi(pszVersion) : 4;
    3236                 : #else
    3237                 :     int iVersion = pszVersion ? atoi(pszVersion) : 3;
    3238                 : #endif
    3239                 :     LT_STATUS eStat = LT_STS_Uninit;
    3240                 : 
    3241                 : #ifdef DEBUG
    3242                 :     bool bMeter = false;
    3243                 : #else
    3244                 :     bool bMeter = true;
    3245                 : #endif    
    3246                 :     
    3247                 :     if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
    3248                 :     {
    3249                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
    3250                 :                   "MrSID driver ignores color table. "
    3251                 :                   "The source raster band will be considered as grey level.\n"
    3252                 :                   "Consider using color table expansion (-expand option in gdal_translate)\n");
    3253                 :         if (bStrict)
    3254                 :             return NULL;
    3255                 :     }
    3256                 : 
    3257                 :     MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
    3258                 :     if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
    3259                 :     {
    3260                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3261                 :                   "MrSIDProgress.setProgressStatus failed.\n%s",
    3262                 :                   getLastStatusString( eStat ) );
    3263                 :         return NULL;
    3264                 :     }
    3265                 : 
    3266                 :     // Create the file.                                               
    3267                 :     MrSIDDummyImageReader oImageReader( poSrcDS );
    3268                 :     if( LT_FAILURE( eStat = oImageReader.initialize() ) )
    3269                 :     {
    3270                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3271                 :                   "MrSIDDummyImageReader.Initialize failed.\n%s",
    3272                 :                   getLastStatusString( eStat ) );
    3273                 :         return NULL;
    3274                 :     }
    3275                 : 
    3276                 :     LTIGeoFileImageWriter *poImageWriter = NULL;
    3277                 :     switch (iVersion)
    3278                 :     {
    3279                 :     case 2: {
    3280                 :         // Output Mrsid Version 2 file.
    3281                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3282                 :         LTIDLLDefault<MG2ImageWriter> *poMG2ImageWriter;
    3283                 :         poMG2ImageWriter = new LTIDLLDefault<MG2ImageWriter>;
    3284                 :         eStat = poMG2ImageWriter->initialize(&oImageReader);
    3285                 : #else
    3286                 :         LTIDLLWriter<MG2ImageWriter> *poMG2ImageWriter;
    3287                 :         poMG2ImageWriter = new LTIDLLWriter<MG2ImageWriter>(&oImageReader);
    3288                 :         eStat = poMG2ImageWriter->initialize();
    3289                 : #endif
    3290                 :         if( LT_FAILURE( eStat ) )
    3291                 :         {
    3292                 :             delete poMG2ImageWriter;
    3293                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3294                 :                       "MG2ImageWriter.initialize() failed.\n%s",
    3295                 :                       getLastStatusString( eStat ) );
    3296                 :             return NULL;
    3297                 :         }
    3298                 : 
    3299                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3300                 :         eStat = poMG2ImageWriter->setEncodingApplication("MrSID Driver",
    3301                 :                                                          GDALVersionInfo("--version"));
    3302                 :         if( LT_FAILURE( eStat ) )
    3303                 :         {
    3304                 :             delete poMG2ImageWriter;
    3305                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3306                 :                       "MG2ImageWriter.setEncodingApplication() failed.\n%s",
    3307                 :                       getLastStatusString( eStat ) );
    3308                 :             return NULL;
    3309                 :         }
    3310                 : #endif
    3311                 : 
    3312                 :         poMG2ImageWriter->setUsageMeterEnabled(bMeter);
    3313                 : 
    3314                 :         poMG2ImageWriter->params().setBlockSize(poMG2ImageWriter->params().getBlockSize());
    3315                 : 
    3316                 :         // check for compression option
    3317                 :         const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
    3318                 :         if( pszValue != NULL )
    3319                 :             poMG2ImageWriter->params().setCompressionRatio( (float)atof(pszValue) );
    3320                 : 
    3321                 :         poImageWriter = poMG2ImageWriter;
    3322                 : 
    3323                 :         break; }
    3324                 :     case 3: {
    3325                 :         // Output Mrsid Version 3 file.
    3326                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3327                 :         LTIDLLDefault<MG3ImageWriter> *poMG3ImageWriter;
    3328                 :         poMG3ImageWriter = new LTIDLLDefault<MG3ImageWriter>;
    3329                 :         eStat = poMG3ImageWriter->initialize(&oImageReader);
    3330                 : #else
    3331                 :         LTIDLLWriter<MG3ImageWriter> *poMG3ImageWriter;
    3332                 :         poMG3ImageWriter = new LTIDLLWriter<MG3ImageWriter>(&oImageReader);
    3333                 :         eStat = poMG3ImageWriter->initialize();
    3334                 : #endif
    3335                 :         if( LT_FAILURE( eStat ) )
    3336                 :         {
    3337                 :             delete poMG3ImageWriter;
    3338                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3339                 :                       "MG3ImageWriter.initialize() failed.\n%s",
    3340                 :                       getLastStatusString( eStat ) );
    3341                 :             return NULL;
    3342                 :         }
    3343                 : 
    3344                 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
    3345                 :         eStat = poMG3ImageWriter->setEncodingApplication("MrSID Driver",
    3346                 :                                                          GDALVersionInfo("--version"));
    3347                 :         if( LT_FAILURE( eStat ) )
    3348                 :         {
    3349                 :             delete poMG3ImageWriter;
    3350                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3351                 :                       "MG3ImageWriter.setEncodingApplication() failed.\n%s",
    3352                 :                       getLastStatusString( eStat ) );
    3353                 :             return NULL;
    3354                 :         }
    3355                 : #endif
    3356                 : 
    3357                 :         // usage meter should only be disabled for debugging
    3358                 :         poMG3ImageWriter->setUsageMeterEnabled(bMeter);
    3359                 : 
    3360                 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3361                 :         // Set 64-bit Interface for large files.
    3362                 :         poMG3ImageWriter->setFileStream64(true);
    3363                 : #endif
    3364                 : 
    3365                 :         // set 2 pass optimizer option
    3366                 :         if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
    3367                 :             poMG3ImageWriter->params().setTwoPassOptimizer( true );
    3368                 : 
    3369                 :         // set filesize in KB
    3370                 :         const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
    3371                 :         if( pszValue != NULL )
    3372                 :             poMG3ImageWriter->params().setTargetFilesize( atoi(pszValue) );
    3373                 : 
    3374                 :         poImageWriter = poMG3ImageWriter;
    3375                 : 
    3376                 :         break; }
    3377                 : #ifdef MRSID_HAVE_MG4WRITE
    3378                 :     case 4: {
    3379                 :         // Output Mrsid Version 4 file.
    3380                 :         LTIDLLDefault<MG4ImageWriter> *poMG4ImageWriter;
    3381                 :         poMG4ImageWriter = new LTIDLLDefault<MG4ImageWriter>;
    3382                 :         eStat = poMG4ImageWriter->initialize(&oImageReader, NULL, NULL);
    3383                 :         if( LT_FAILURE( eStat ) )
    3384                 :         {
    3385                 :             delete poMG4ImageWriter;
    3386                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3387                 :                       "MG3ImageWriter.initialize() failed.\n%s",
    3388                 :                       getLastStatusString( eStat ) );
    3389                 :             return NULL;
    3390                 :         }
    3391                 : 
    3392                 :         eStat = poMG4ImageWriter->setEncodingApplication("MrSID Driver",
    3393                 :                                                          GDALVersionInfo("--version"));
    3394                 :         if( LT_FAILURE( eStat ) )
    3395                 :         {
    3396                 :             delete poMG4ImageWriter;
    3397                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3398                 :                       "MG3ImageWriter.setEncodingApplication() failed.\n%s",
    3399                 :                       getLastStatusString( eStat ) );
    3400                 :             return NULL;
    3401                 :         }
    3402                 : 
    3403                 :         // usage meter should only be disabled for debugging
    3404                 :         poMG4ImageWriter->setUsageMeterEnabled(bMeter);
    3405                 : 
    3406                 :         // set 2 pass optimizer option
    3407                 :         if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
    3408                 :             poMG4ImageWriter->params().setTwoPassOptimizer( true );
    3409                 : 
    3410                 :         // set filesize in KB
    3411                 :         const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
    3412                 :         if( pszValue != NULL )
    3413                 :             poMG4ImageWriter->params().setTargetFilesize( atoi(pszValue) );
    3414                 : 
    3415                 :         poImageWriter = poMG4ImageWriter;
    3416                 : 
    3417                 :         break; }
    3418                 : #endif /* MRSID_HAVE_MG4WRITE */
    3419                 :     default:
    3420                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3421                 :                   "Invalid MrSID generation specified (VERSION=%s).",
    3422                 :                   pszVersion );
    3423                 :         return NULL;
    3424                 :     }
    3425                 : 
    3426                 :     // set output filename
    3427                 :     poImageWriter->setOutputFileSpec( pszFilename );
    3428                 : 
    3429                 :     // set progress delegate
    3430                 :     poImageWriter->setProgressDelegate(&oProgressDelegate);
    3431                 : 
    3432                 :     // set defaults
    3433                 :     poImageWriter->setStripHeight(poImageWriter->getStripHeight());
    3434                 : 
    3435                 :     // set MrSID world file
    3436                 :     if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
    3437                 :         poImageWriter->setWorldFileSupport( true );
    3438                 : 
    3439                 :     // write the scene
    3440                 :     int nXSize = poSrcDS->GetRasterXSize();
    3441                 :     int nYSize = poSrcDS->GetRasterYSize();
    3442                 :     const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
    3443                 :     if( LT_FAILURE( eStat = poImageWriter->write( oScene ) ) )
    3444                 :     {
    3445                 :         delete poImageWriter;
    3446                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3447                 :                   "MG2ImageWriter.write() failed.\n%s",
    3448                 :                   getLastStatusString( eStat ) );
    3449                 :         return NULL;
    3450                 :     }
    3451                 : 
    3452                 :     delete poImageWriter;
    3453                 : /* -------------------------------------------------------------------- */
    3454                 : /*      Re-open dataset, and copy any auxilary pam information.         */
    3455                 : /* -------------------------------------------------------------------- */
    3456                 :     GDALPamDataset *poDS = (GDALPamDataset *) 
    3457                 :         GDALOpen( pszFilename, GA_ReadOnly );
    3458                 : 
    3459                 :     if( poDS )
    3460                 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    3461                 : 
    3462                 :     return poDS;
    3463                 : }
    3464                 : 
    3465                 : #ifdef MRSID_J2K
    3466                 : /************************************************************************/
    3467                 : /*                           JP2CreateCopy()                            */
    3468                 : /************************************************************************/
    3469                 : 
    3470                 : static GDALDataset *
    3471                 : JP2CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
    3472                 :                  int bStrict, char ** papszOptions, 
    3473                 :                  GDALProgressFunc pfnProgress, void * pProgressData )
    3474                 : 
    3475                 : { 
    3476                 : #ifdef DEBUG
    3477                 :     bool bMeter = false;
    3478                 : #else
    3479                 :     bool bMeter = true;
    3480                 : #endif    
    3481                 : 
    3482                 :     int nXSize = poSrcDS->GetRasterXSize();
    3483                 :     int nYSize = poSrcDS->GetRasterYSize();
    3484                 :     LT_STATUS  eStat;
    3485                 :     
    3486                 :     if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
    3487                 :     {
    3488                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
    3489                 :                   "MrSID driver ignores color table. "
    3490                 :                   "The source raster band will be considered as grey level.\n"
    3491                 :                   "Consider using color table expansion (-expand option in gdal_translate)\n");
    3492                 :         if (bStrict)
    3493                 :             return NULL;
    3494                 :     }
    3495                 : 
    3496                 :     MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
    3497                 :     if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
    3498                 :     {
    3499                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3500                 :                   "MrSIDProgress.setProgressStatus failed.\n%s",
    3501                 :                   getLastStatusString( eStat ) );
    3502                 :         return NULL;
    3503                 :     }
    3504                 : 
    3505                 :     // Create the file.   
    3506                 :     MrSIDDummyImageReader oImageReader( poSrcDS );
    3507                 :     eStat = oImageReader.initialize();
    3508                 :     if( eStat != LT_STS_Success )
    3509                 :     {
    3510                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3511                 :                   "MrSIDDummyImageReader.Initialize failed.\n%s",
    3512                 :                   getLastStatusString( eStat ) );
    3513                 :         return NULL;
    3514                 :     }
    3515                 :       
    3516                 : #if !defined(MRSID_POST5)
    3517                 :     J2KImageWriter oImageWriter(&oImageReader);
    3518                 :     eStat = oImageWriter.initialize();
    3519                 : #elif !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3520                 :     JP2WriterManager oImageWriter(&oImageReader);
    3521                 :     eStat = oImageWriter.initialize();
    3522                 : #else
    3523                 :     JP2WriterManager oImageWriter;
    3524                 :     eStat = oImageWriter.initialize(&oImageReader);
    3525                 : #endif
    3526                 :     if( eStat != LT_STS_Success )
    3527                 :     {
    3528                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3529                 :                   "J2KImageWriter.Initialize failed.\n%s",
    3530                 :                   getLastStatusString( eStat ) );
    3531                 :         return NULL;
    3532                 :     }
    3533                 : 
    3534                 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
    3535                 :     // Set 64-bit Interface for large files.
    3536                 :     oImageWriter.setFileStream64(true);
    3537                 : #endif
    3538                 : 
    3539                 :     oImageWriter.setUsageMeterEnabled(bMeter);
    3540                 :       
    3541                 :     // set output filename
    3542                 :     oImageWriter.setOutputFileSpec( pszFilename );
    3543                 : 
    3544                 :     // set progress delegate
    3545                 :     oImageWriter.setProgressDelegate(&oProgressDelegate);
    3546                 : 
    3547                 :     // Set defaults
    3548                 :     //oImageWriter.setStripHeight(oImageWriter.getStripHeight());
    3549                 : 
    3550                 :     // set MrSID world file
    3551                 :     if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
    3552                 :         oImageWriter.setWorldFileSupport( true );
    3553                 :       
    3554                 :     // check for compression option
    3555                 :     const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
    3556                 :     if( pszValue != NULL )
    3557                 :         oImageWriter.params().setCompressionRatio( (float)atof(pszValue) );
    3558                 :         
    3559                 :     pszValue = CSLFetchNameValue(papszOptions, "XMLPROFILE");
    3560                 :     if( pszValue != NULL )
    3561                 :     {
    3562                 :         LTFileSpec xmlprofile(pszValue);
    3563                 :         eStat = oImageWriter.params().readProfile(xmlprofile);
    3564                 :         if( eStat != LT_STS_Success )
    3565                 :         {
    3566                 :             CPLError( CE_Failure, CPLE_AppDefined,
    3567                 :                       "JPCWriterParams.readProfile failed.\n%s",
    3568                 :                       getLastStatusString( eStat ) );
    3569                 :             return NULL;
    3570                 :         }
    3571                 :     }
    3572                 : 
    3573                 :     // write the scene
    3574                 :     const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
    3575                 :     eStat = oImageWriter.write( oScene );
    3576                 :     if( eStat != LT_STS_Success )
    3577                 :     {
    3578                 :         CPLError( CE_Failure, CPLE_AppDefined,
    3579                 :                   "J2KImageWriter.write() failed.\n%s",
    3580                 :                   getLastStatusString( eStat ) );
    3581                 :         return NULL;
    3582                 :     }
    3583                 :   
    3584                 : /* -------------------------------------------------------------------- */
    3585                 : /*      Re-open dataset, and copy any auxilary pam information.         */
    3586                 : /* -------------------------------------------------------------------- */
    3587                 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
    3588                 :     GDALPamDataset *poDS = (GDALPamDataset*) JP2Open(&oOpenInfo);
    3589                 : 
    3590                 :     if( poDS )  
    3591                 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
    3592                 : 
    3593                 :     return poDS;
    3594                 : }
    3595                 : #endif /* MRSID_J2K */
    3596                 : #endif /* MRSID_ESDK */
    3597                 : 
    3598                 : /************************************************************************/
    3599                 : /*                        GDALRegister_MrSID()                          */
    3600                 : /************************************************************************/
    3601                 : 
    3602             558 : void GDALRegister_MrSID()
    3603                 : 
    3604                 : {
    3605                 :     GDALDriver  *poDriver;
    3606                 :     
    3607             558 :     if (! GDAL_CHECK_VERSION("MrSID driver"))
    3608               0 :         return;
    3609                 : 
    3610                 : /* -------------------------------------------------------------------- */
    3611                 : /*      MrSID driver.                                                   */
    3612                 : /* -------------------------------------------------------------------- */
    3613             558 :     if( GDALGetDriverByName( "MrSID" ) == NULL )
    3614                 :     {
    3615             537 :         poDriver = new GDALDriver();
    3616                 : 
    3617             537 :         poDriver->SetDescription( "MrSID" );
    3618                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    3619             537 :                         "Multi-resolution Seamless Image Database (MrSID)" );
    3620             537 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_mrsid.html" );
    3621             537 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "sid" );
    3622                 : 
    3623                 : #ifdef MRSID_ESDK
    3624                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    3625                 :                                    "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
    3626                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    3627                 : "<CreationOptionList>"
    3628                 : // Version 2 Options
    3629                 : "   <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
    3630                 : // Version 3 Options
    3631                 : "   <Option name='TWOPASS' type='int' description='Use twopass optimizer algorithm'/>"
    3632                 : "   <Option name='FILESIZE' type='int' description='Set target file size (0 implies lossless compression)'/>"
    3633                 : // Version 2 and 3 Option
    3634                 : "   <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
    3635                 : // Version Type
    3636                 : "   <Option name='VERSION' type='int' description='Valid versions are 2 and 3, default = 3'/>"
    3637                 : "</CreationOptionList>" );
    3638                 : 
    3639                 :         poDriver->pfnCreateCopy = MrSIDCreateCopy;
    3640                 : 
    3641                 : #else
    3642                 :         /* In read-only mode, we support VirtualIO. I don't think this is the case */
    3643                 :         /* for MrSIDCreateCopy() */
    3644             537 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    3645                 : #endif
    3646             537 :         poDriver->pfnIdentify = MrSIDIdentify;
    3647             537 :         poDriver->pfnOpen = MrSIDOpen;
    3648                 : 
    3649             537 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    3650                 :     }
    3651                 : 
    3652                 : /* -------------------------------------------------------------------- */
    3653                 : /*      JP2MRSID driver.                                                */
    3654                 : /* -------------------------------------------------------------------- */
    3655                 : #ifdef MRSID_J2K
    3656             558 :     if( GDALGetDriverByName( "JP2MrSID" ) == NULL )
    3657                 :     {
    3658             537 :         poDriver = new GDALDriver();
    3659                 : 
    3660             537 :         poDriver->SetDescription( "JP2MrSID" );
    3661                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
    3662             537 :                         "MrSID JPEG2000" );
    3663             537 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_jp2mrsid.html" );
    3664             537 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
    3665                 : 
    3666                 : #ifdef MRSID_ESDK
    3667                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    3668                 :                                    "Byte Int16 UInt16" );
    3669                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
    3670                 : "<CreationOptionList>"
    3671                 : "   <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
    3672                 : "   <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
    3673                 : "   <Option name='XMLPROFILE' type='string' description='Use named xml profile file'/>"
    3674                 : "</CreationOptionList>" );
    3675                 : 
    3676                 :         poDriver->pfnCreateCopy = JP2CreateCopy;
    3677                 : #else
    3678                 :         /* In read-only mode, we support VirtualIO. I don't think this is the case */
    3679                 :         /* for JP2CreateCopy() */
    3680             537 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    3681                 : #endif
    3682             537 :         poDriver->pfnIdentify = JP2Identify;
    3683             537 :         poDriver->pfnOpen = JP2Open;
    3684                 : 
    3685             537 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    3686                 :     }
    3687                 : #endif /* def MRSID_J2K */
    3688                 : }
    3689                 : 
    3690                 : #if defined(MRSID_USE_TIFFSYMS_WORKAROUND)
    3691                 : extern "C" {
    3692                 : 
    3693                 : /* This is not pretty but I am not sure how else to get the plugin to build
    3694                 :  * against the ESDK.  ESDK symbol dependencies bring in __TIFFmemcpy and
    3695                 :  * __gtiff_size, which are not exported from gdal.dll.  Rather than link these
    3696                 :  * symbols from the ESDK distribution of GDAL, or link in the entire gdal.lib
    3697                 :  * statically, it seemed safer and smaller to bring in just the objects that
    3698                 :  * wouldsatisfy these symbols from the enclosing GDAL build.  However, doing
    3699                 :  * so pulls in a few more dependencies.  /Gy and /OPT:REF did not seem to help
    3700                 :  * things, so I have implemented no-op versions of these symbols since they
    3701                 :  * do not actually get called.  If the MrSID ESDK ever comes to require the
    3702                 :  * actual versions of these functions, we'll hope duplicate symbol errors will
    3703                 :  * bring attention back to this problem.
    3704                 :  */
    3705                 : void TIFFClientOpen() {}
    3706                 : void TIFFError() {}
    3707                 : void TIFFGetField() {}
    3708                 : void TIFFSetField() {}
    3709                 : 
    3710                 : }
    3711                 : #endif
    3712                 : 

Generated by: LCOV version 1.7