LCOV - code coverage report
Current view: directory - frmts/ecw - ecwdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 519 418 80.5 %
Date: 2010-01-09 Functions: 38 34 89.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: ecwdataset.cpp 17906 2009-10-26 19:47:21Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL 
       5                 :  * Purpose:  ECW (ERMapper Wavelet Compression Format) Driver
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_pam.h"
      31                 : #include "gdaljp2metadata.h"
      32                 : #include "ogr_spatialref.h"
      33                 : #include "cpl_string.h"
      34                 : #include "cpl_conv.h"
      35                 : #include "vsiiostream.h"
      36                 : #include "cpl_multiproc.h"
      37                 : #include "cpl_minixml.h"
      38                 : #include "ogr_api.h"
      39                 : #include "ogr_geometry.h"
      40                 : 
      41                 : CPL_CVSID("$Id: ecwdataset.cpp 17906 2009-10-26 19:47:21Z rouault $");
      42                 : 
      43                 : #ifdef FRMT_ecw
      44                 : 
      45                 : static const unsigned char jpc_header[] = {0xff,0x4f};
      46                 : static const unsigned char jp2_header[] = 
      47                 :     {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
      48                 : 
      49                 : static void *hECWDatasetMutex = NULL;
      50                 : static int    bNCSInitialized = FALSE;
      51                 : 
      52                 : CPL_C_START
      53                 : CPLErr CPL_DLL GTIFMemBufFromWkt( const char *pszWKT, 
      54                 :                                   const double *padfGeoTransform,
      55                 :                                   int nGCPCount, const GDAL_GCP *pasGCPList,
      56                 :                                   int *pnSize, unsigned char **ppabyBuffer );
      57                 : CPLErr CPL_DLL GTIFWktFromMemBuf( int nSize, unsigned char *pabyBuffer, 
      58                 :                           char **ppszWKT, double *padfGeoTransform,
      59                 :                           int *pnGCPCount, GDAL_GCP **ppasGCPList );
      60                 : CPL_C_END
      61                 : 
      62                 : void ECWInitialize( void );
      63                 : 
      64                 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo);
      65                 : 
      66                 : /************************************************************************/
      67                 : /* ==================================================================== */
      68                 : /*        ECWDataset        */
      69                 : /* ==================================================================== */
      70                 : /************************************************************************/
      71                 : 
      72                 : class ECWRasterBand;
      73                 : 
      74                 : class CPL_DLL ECWDataset : public GDALPamDataset
      75                 : {
      76                 :     friend class ECWRasterBand;
      77                 : 
      78                 :     CNCSJP2FileView *poFileView;
      79                 :     NCSFileViewFileInfoEx *psFileInfo;
      80                 : 
      81                 :     GDALDataType eRasterDataType;
      82                 :     NCSEcwCellType eNCSRequestDataType;
      83                 : 
      84                 :     int         bUsingCustomStream;
      85                 : 
      86                 :     // Current view window. 
      87                 :     int         bWinActive;
      88                 :     int         nWinXOff, nWinYOff, nWinXSize, nWinYSize;
      89                 :     int         nWinBufXSize, nWinBufYSize;
      90                 :     int         nWinBandCount;
      91                 :     int         *panWinBandList;
      92                 :     int         nWinBufLoaded;
      93                 :     void        **papCurLineBuf;
      94                 : 
      95                 :     int         bGeoTransformValid;
      96                 :     double      adfGeoTransform[6];
      97                 :     char        *pszProjection;
      98                 :     int         nGCPCount;
      99                 :     GDAL_GCP    *pasGCPList;
     100                 : 
     101                 :     char        **papszGMLMetadata;
     102                 : 
     103                 :     void        ECW2WKTProjection();
     104                 : 
     105                 :     void        CleanupWindow();
     106                 :     int         TryWinRasterIO( GDALRWFlag, int, int, int, int,
     107                 :                                 GByte *, int, int, GDALDataType,
     108                 :                                 int, int *, int, int, int );
     109                 :     CPLErr      LoadNextLine();
     110                 : 
     111                 :   public:
     112                 :     ECWDataset(int bIsJPEG2000);
     113                 :     ~ECWDataset();
     114                 :                 
     115                 :     static GDALDataset *Open( GDALOpenInfo *, int bIsJPEG2000 );
     116                 :     static int          IdentifyJPEG2000( GDALOpenInfo * poOpenInfo );
     117                 :     static GDALDataset *OpenJPEG2000( GDALOpenInfo * );
     118                 :     static int          IdentifyECW( GDALOpenInfo * poOpenInfo );
     119                 :     static GDALDataset *OpenECW( GDALOpenInfo * );
     120                 : 
     121                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
     122                 :                               void *, int, int, GDALDataType,
     123                 :                               int, int *, int, int, int );
     124                 : 
     125                 :     virtual CPLErr GetGeoTransform( double * );
     126                 :     virtual const char *GetProjectionRef();
     127                 : 
     128                 :     virtual int    GetGCPCount();
     129                 :     virtual const char *GetGCPProjection();
     130                 :     virtual const GDAL_GCP *GetGCPs();
     131                 : 
     132                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
     133                 : 
     134                 :     virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     135                 :                                int nBufXSize, int nBufYSize, 
     136                 :                                GDALDataType eDT, 
     137                 :                                int nBandCount, int *panBandList,
     138                 :                                char **papszOptions );
     139                 : };
     140                 : 
     141                 : /************************************************************************/
     142                 : /* ==================================================================== */
     143                 : /*                            ECWRasterBand                             */
     144                 : /* ==================================================================== */
     145                 : /************************************************************************/
     146                 : 
     147                 : class ECWRasterBand : public GDALPamRasterBand
     148                 : {
     149                 :     friend class ECWDataset;
     150                 :     
     151                 :     // NOTE: poDS may be altered for NITF/JPEG2000 files!
     152                 :     ECWDataset     *poGDS;
     153                 : 
     154                 :     GDALColorInterp         eBandInterp;
     155                 : 
     156                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
     157                 :                               void *, int, int, GDALDataType,
     158                 :                               int, int );
     159                 : 
     160                 :   public:
     161                 : 
     162                 :                    ECWRasterBand( ECWDataset *, int );
     163                 :                    ~ECWRasterBand();
     164                 : 
     165                 :     virtual CPLErr IReadBlock( int, int, void * );
     166               0 :     virtual int    HasArbitraryOverviews() { return TRUE; }
     167                 :     virtual GDALColorInterp GetColorInterpretation();
     168                 :     virtual CPLErr SetColorInterpretation( GDALColorInterp );
     169                 : 
     170                 :     virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     171                 :                                int nBufXSize, int nBufYSize, 
     172                 :                                GDALDataType eDT, char **papszOptions );
     173                 : };
     174                 : 
     175                 : /************************************************************************/
     176                 : /*                           ECWRasterBand()                            */
     177                 : /************************************************************************/
     178                 : 
     179              91 : ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand )
     180                 : 
     181                 : {
     182              91 :     this->poDS = poDS;
     183              91 :     poGDS = poDS;
     184                 : 
     185              91 :     this->nBand = nBand;
     186              91 :     eDataType = poDS->eRasterDataType;
     187              91 :     nBlockXSize = poDS->GetRasterXSize();
     188              91 :     nBlockYSize = 1;
     189                 : 
     190                 : /* -------------------------------------------------------------------- */
     191                 : /*      Work out band color interpretation.                             */
     192                 : /* -------------------------------------------------------------------- */
     193              91 :     if( poDS->psFileInfo->eColorSpace == NCSCS_NONE )
     194               0 :         eBandInterp = GCI_Undefined;
     195              91 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_GREYSCALE )
     196              12 :         eBandInterp = GCI_GrayIndex;
     197              79 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND )
     198              27 :         eBandInterp = GCI_Undefined;
     199              52 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_sRGB )
     200                 :     {
     201              52 :         if( nBand == 1 )
     202              17 :             eBandInterp = GCI_RedBand;
     203              35 :         else if( nBand == 2 )
     204              17 :             eBandInterp = GCI_GreenBand;
     205              18 :         else if( nBand == 3 )
     206              17 :             eBandInterp = GCI_BlueBand;
     207                 :         else
     208               1 :             eBandInterp = GCI_Undefined;
     209                 :     }
     210               0 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
     211                 :     {
     212               0 :         if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
     213                 :         {
     214               0 :             if( nBand == 1 )
     215               0 :                 eBandInterp = GCI_RedBand;
     216               0 :             else if( nBand == 2 )
     217               0 :                 eBandInterp = GCI_GreenBand;
     218               0 :             else if( nBand == 3 )
     219               0 :                 eBandInterp = GCI_BlueBand;
     220                 :             else
     221               0 :                 eBandInterp = GCI_Undefined;
     222                 :         }
     223                 :         else
     224                 :         {
     225               0 :             if( nBand == 1 )
     226               0 :                 eBandInterp = GCI_YCbCr_YBand;
     227               0 :             else if( nBand == 2 )
     228               0 :                 eBandInterp = GCI_YCbCr_CbBand;
     229               0 :             else if( nBand == 3 )
     230               0 :                 eBandInterp = GCI_YCbCr_CrBand;
     231                 :             else
     232               0 :                 eBandInterp = GCI_Undefined;
     233                 :         }
     234                 :     }
     235                 :     else
     236               0 :         eBandInterp = GCI_Undefined;
     237              91 : }
     238                 : 
     239                 : /************************************************************************/
     240                 : /*                          ~ECWRasterBand()                           */
     241                 : /************************************************************************/
     242                 : 
     243             182 : ECWRasterBand::~ECWRasterBand()
     244                 : 
     245                 : {
     246              91 :     FlushCache();
     247             182 : }
     248                 : 
     249                 : /************************************************************************/
     250                 : /*                       GetColorInterpretation()                       */
     251                 : /************************************************************************/
     252                 : 
     253              47 : GDALColorInterp ECWRasterBand::GetColorInterpretation()
     254                 : 
     255                 : {
     256              47 :     return eBandInterp;
     257                 : }
     258                 : 
     259                 : /************************************************************************/
     260                 : /*                       SetColorInterpretation()                       */
     261                 : /*                                                                      */
     262                 : /*      This would normally just be used by folks using the ECW code    */
     263                 : /*      to read JP2 streams in other formats (such as NITF) and         */
     264                 : /*      providing their own color interpretation regardless of what     */
     265                 : /*      ECW might think the stream itself says.                         */
     266                 : /************************************************************************/
     267                 : 
     268               0 : CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
     269                 : 
     270                 : {
     271               0 :     eBandInterp = eNewInterp;
     272                 : 
     273               0 :     return CE_None;
     274                 : }
     275                 : 
     276                 : /************************************************************************/
     277                 : /*                             AdviseRead()                             */
     278                 : /************************************************************************/
     279                 : 
     280              31 : CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     281                 :                                   int nBufXSize, int nBufYSize, 
     282                 :                                   GDALDataType eDT, 
     283                 :                                   char **papszOptions )
     284                 : {
     285                 :     return poGDS->AdviseRead( nXOff, nYOff, nXSize, nYSize, 
     286                 :                               nBufXSize, nBufYSize, eDT, 
     287              31 :                               1, &nBand, papszOptions );
     288                 : }
     289                 : 
     290                 : /************************************************************************/
     291                 : /*                             IRasterIO()                              */
     292                 : /************************************************************************/
     293                 : 
     294           11723 : CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     295                 :                                  int nXOff, int nYOff, int nXSize, int nYSize,
     296                 :                                  void * pData, int nBufXSize, int nBufYSize,
     297                 :                                  GDALDataType eBufType,
     298                 :                                  int nPixelSpace, int nLineSpace )
     299                 :     
     300                 : {
     301                 :     int          iBand, bDirect;
     302           11723 :     int          nNewXSize = nBufXSize, nNewYSize = nBufYSize;
     303           11723 :     GByte        *pabyWorkBuffer = NULL;
     304                 : 
     305                 : /* -------------------------------------------------------------------- */
     306                 : /*      Try to do it based on existing "advised" access.                */
     307                 : /* -------------------------------------------------------------------- */
     308           11723 :     if( poGDS->TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
     309                 :                                (GByte *) pData, nBufXSize, nBufYSize, 
     310                 :                                eBufType, 1, &nBand, 
     311                 :                                nPixelSpace, nLineSpace, 0 ) )
     312           11689 :         return CE_None;
     313                 : 
     314                 : /* -------------------------------------------------------------------- */
     315                 : /*      We will drop down to the block oriented API if only a single    */
     316                 : /*      scanline was requested. This is based on the assumption that    */
     317                 : /*      doing lots of single scanline windows is expensive.             */
     318                 : /* -------------------------------------------------------------------- */
     319              34 :     if( nYSize == 1 )
     320                 :     {
     321                 : #ifdef notdef
     322                 :         CPLDebug( "ECWRasterBand", 
     323                 :                   "RasterIO(%d,%d,%d,%d -> %dx%d) - redirected.", 
     324                 :                   nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     325                 : #endif
     326                 :         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     327                 :                                          pData, nBufXSize, nBufYSize, 
     328              31 :                                          eBufType, nPixelSpace, nLineSpace );
     329                 :     }
     330                 : 
     331                 :     CPLDebug( "ECWRasterBand", 
     332                 :               "RasterIO(nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)", 
     333               3 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     334                 : 
     335                 : 
     336               3 :     if ( nXSize < nBufXSize )
     337               0 :             nNewXSize = nXSize;
     338                 : 
     339               3 :     if ( nYSize < nBufYSize )
     340               0 :             nNewYSize = nYSize;
     341                 : 
     342                 : /* -------------------------------------------------------------------- */
     343                 : /*      Default line and pixel spacing if needed.                       */
     344                 : /* -------------------------------------------------------------------- */
     345               3 :     if ( nPixelSpace == 0 )
     346               0 :         nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
     347                 : 
     348               3 :     if ( nLineSpace == 0 )
     349               0 :         nLineSpace = nPixelSpace * nBufXSize;
     350                 : 
     351                 : /* -------------------------------------------------------------------- */
     352                 : /*      Can we perform direct loads, or must we load into a working     */
     353                 : /*      buffer, and transform?                                          */
     354                 : /* -------------------------------------------------------------------- */
     355               3 :     int     nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
     356                 : 
     357                 :     bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
     358               3 :       && nNewXSize == nBufXSize && nNewYSize == nBufYSize;
     359               3 :     if( !bDirect )
     360               1 :         pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
     361                 : 
     362                 : /* -------------------------------------------------------------------- */
     363                 : /*      Establish access at the desired resolution.                     */
     364                 : /* -------------------------------------------------------------------- */
     365               3 :     CNCSError oErr;
     366                 : 
     367               3 :     poGDS->CleanupWindow();
     368                 : 
     369               3 :     iBand = nBand-1;
     370                 :     oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
     371                 :                                        nXOff, nYOff, 
     372                 :                                        nXOff + nXSize - 1, 
     373                 :                                        nYOff + nYSize - 1,
     374               3 :                                        nNewXSize, nNewYSize );
     375               3 :     if( oErr.GetErrorNumber() != NCS_SUCCESS )
     376                 :     {
     377               0 :         CPLFree( pabyWorkBuffer );
     378               0 :         char* pszErrorMessage = oErr.GetErrorMessage();
     379                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     380               0 :                   "%s", pszErrorMessage );
     381               0 :         NCSFree(pszErrorMessage);
     382                 :         
     383               0 :         return CE_Failure;
     384                 :     }
     385                 : 
     386                 : /* -------------------------------------------------------------------- */
     387                 : /*      Read back one scanline at a time, till request is satisfied.    */
     388                 : /*      Supersampling is not supported by the ECW API, so we will do    */
     389                 : /*      it ourselves.                                                   */
     390                 : /* -------------------------------------------------------------------- */
     391               3 :     double  dfSrcYInc = (double)nNewYSize / nBufYSize;
     392               3 :     double  dfSrcXInc = (double)nNewXSize / nBufXSize;
     393                 :     int         iSrcLine, iDstLine;
     394                 : 
     395             759 :     for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
     396                 :     {
     397                 :         NCSEcwReadStatus eRStatus;
     398             756 :         int         iDstLineOff = iDstLine * nLineSpace;
     399                 :         unsigned char *pabySrcBuf;
     400                 : 
     401             756 :         if( bDirect )
     402             736 :             pabySrcBuf = ((GByte *)pData) + iDstLineOff;
     403                 :         else
     404              20 :             pabySrcBuf = pabyWorkBuffer;
     405                 : 
     406            1512 :   if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
     407                 :   {
     408                 :             eRStatus = poGDS->poFileView->ReadLineBIL( 
     409             756 :                 poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
     410                 : 
     411             756 :       if( eRStatus != NCSECW_READ_OK )
     412                 :       {
     413               0 :           CPLFree( pabyWorkBuffer );
     414                 :           CPLError( CE_Failure, CPLE_AppDefined,
     415               0 :         "NCScbmReadViewLineBIL failed." );
     416               0 :     return CE_Failure;
     417                 :       }
     418                 : 
     419             756 :             if( !bDirect )
     420                 :             {
     421              20 :                 if ( nNewXSize == nBufXSize )
     422                 :                 {
     423                 :                     GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType, 
     424                 :                                    nRawPixelSize, 
     425                 :                                    ((GByte *)pData) + iDstLine * nLineSpace, 
     426              20 :                                    eBufType, nPixelSpace, nBufXSize );
     427                 :                 }
     428                 :     else
     429                 :     {
     430                 :               int iPixel;
     431                 : 
     432               0 :                     for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
     433                 :                     {
     434                 :                         GDALCopyWords( pabyWorkBuffer 
     435                 :                                        + nRawPixelSize*((int)(iPixel*dfSrcXInc)),
     436                 :                                        poGDS->eRasterDataType, nRawPixelSize,
     437                 :                                        (GByte *)pData + iDstLineOff
     438                 :                + iPixel * nPixelSpace,
     439               0 :                                        eBufType, nPixelSpace, 1 );
     440                 :                     }
     441                 :     }
     442                 :             }
     443                 : 
     444             756 :             iSrcLine++;
     445                 :   }
     446                 :   else
     447                 :   {
     448                 :       // Just copy the previous line in this case
     449                 :             GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
     450                 :                             eBufType, nPixelSpace,
     451                 :                             (GByte *)pData + iDstLineOff,
     452               0 :                             eBufType, nPixelSpace, nBufXSize );
     453                 :   }
     454                 :     }
     455                 : 
     456               3 :     CPLFree( pabyWorkBuffer );
     457                 : 
     458               3 :     return CE_None;
     459                 : }
     460                 : 
     461                 : /************************************************************************/
     462                 : /*                             IReadBlock()                             */
     463                 : /************************************************************************/
     464                 : 
     465              31 : CPLErr ECWRasterBand::IReadBlock( int, int nBlockYOff, void * pImage )
     466                 : 
     467                 : {
     468              31 :     CPLErr eErr = CE_None;
     469                 : 
     470              31 :     if( poGDS->TryWinRasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1, 
     471                 :                                (GByte *) pImage, nBlockXSize, 1, 
     472                 :                                eDataType, 1, &nBand, 0, 0, 0 ) )
     473               0 :         return CE_None;
     474                 : 
     475                 :     eErr = AdviseRead( 0, nBlockYOff, nRasterXSize, nRasterYSize - nBlockYOff,
     476                 :                        nRasterXSize, nRasterYSize - nBlockYOff, 
     477              31 :                        eDataType, NULL );
     478              31 :     if( eErr != CE_None )
     479               0 :         return eErr;
     480                 : 
     481              31 :     if( poGDS->TryWinRasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1, 
     482                 :                                (GByte *) pImage, nBlockXSize, 1, 
     483                 :                                eDataType, 1, &nBand, 0, 0, 0 ) )
     484              31 :         return CE_None;
     485                 : 
     486                 :     CPLError( CE_Failure, CPLE_AppDefined, 
     487                 :               "TryWinRasterIO() failed for blocked scanline %d of band %d.",
     488               0 :               nBlockYOff, nBand );
     489               0 :     return CE_Failure;
     490                 : }
     491                 : 
     492                 : /************************************************************************/
     493                 : /* ==================================================================== */
     494                 : /*                            ECWDataset                               */
     495                 : /* ==================================================================== */
     496                 : /************************************************************************/
     497                 : 
     498                 : 
     499                 : /************************************************************************/
     500                 : /*                            ECWDataset()                              */
     501                 : /************************************************************************/
     502                 : 
     503              43 : ECWDataset::ECWDataset(int bIsJPEG2000)
     504                 : 
     505                 : {
     506              43 :     bUsingCustomStream = FALSE;
     507              43 :     pszProjection = NULL;
     508              43 :     poFileView = NULL;
     509              43 :     bWinActive = FALSE;
     510              43 :     panWinBandList = NULL;
     511              43 :     eRasterDataType = GDT_Byte;
     512              43 :     nGCPCount = 0;
     513              43 :     pasGCPList = NULL;
     514              43 :     papszGMLMetadata = NULL;
     515                 :     
     516              43 :     bGeoTransformValid = FALSE;
     517              43 :     adfGeoTransform[0] = 0.0;
     518              43 :     adfGeoTransform[1] = 1.0;
     519              43 :     adfGeoTransform[2] = 0.0;
     520              43 :     adfGeoTransform[3] = 0.0;
     521              43 :     adfGeoTransform[4] = 0.0;
     522              43 :     adfGeoTransform[5] = 1.0;
     523                 :     
     524              43 :     poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
     525              43 : }
     526                 : 
     527                 : /************************************************************************/
     528                 : /*                           ~ECWDataset()                              */
     529                 : /************************************************************************/
     530                 : 
     531              86 : ECWDataset::~ECWDataset()
     532                 : 
     533                 : {
     534              43 :     FlushCache();
     535              43 :     CleanupWindow();
     536              43 :     CPLFree( pszProjection );
     537              43 :     CSLDestroy( papszGMLMetadata );
     538                 : 
     539              43 :     if( nGCPCount > 0 )
     540                 :     {
     541               4 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     542               4 :         CPLFree( pasGCPList );
     543                 :     }
     544                 : 
     545                 : /* -------------------------------------------------------------------- */
     546                 : /*      Release / dereference iostream.                                 */
     547                 : /* -------------------------------------------------------------------- */
     548                 :     // The underlying iostream of the CNCSJP2FileView (poFileView) object may 
     549                 :     // also be the underlying iostream of other CNCSJP2FileView (poFileView) 
     550                 :     // objects.  Consequently, when we delete the CNCSJP2FileView (poFileView) 
     551                 :     // object, we must decrement the nFileViewCount attribute of the underlying
     552                 :     // VSIIOStream object, and only delete the VSIIOStream object when 
     553                 :     // nFileViewCount is equal to zero.
     554                 : 
     555              43 :     CPLMutexHolder oHolder( &hECWDatasetMutex );
     556                 : 
     557              43 :     if( poFileView != NULL )
     558                 :     {
     559              43 :         VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
     560                 : 
     561              43 :         poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
     562              43 :         delete poFileView;
     563                 : 
     564              43 :         if( bUsingCustomStream )
     565                 :         {
     566              12 :             if( --poUnderlyingIOStream->nFileViewCount == 0 )
     567              12 :                 delete poUnderlyingIOStream;
     568                 :         }
     569              43 :     }
     570              86 : }
     571                 : 
     572                 : /************************************************************************/
     573                 : /*                             AdviseRead()                             */
     574                 : /************************************************************************/
     575                 : 
     576              32 : CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     577                 :                                int nBufXSize, int nBufYSize, 
     578                 :                                GDALDataType eDT, 
     579                 :                                int nBandCount, int *panBandList,
     580                 :                                char **papszOptions )
     581                 : 
     582                 : {
     583              32 :     int *panAdjustedBandList = NULL;
     584                 : 
     585                 :     CPLDebug( "ECW",
     586                 :               "ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
     587              32 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     588                 : 
     589              32 :     if( nBufXSize > nXSize || nBufYSize > nYSize )
     590                 :     {
     591                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     592                 :                   "Supersampling not directly supported by ECW toolkit,\n"
     593               0 :                   "ignoring AdviseRead() request." );
     594               0 :         return CE_Warning; 
     595                 :     }
     596                 : 
     597                 : /* -------------------------------------------------------------------- */
     598                 : /*      Adjust band numbers to be zero based.                           */
     599                 : /* -------------------------------------------------------------------- */
     600                 :     panAdjustedBandList = (int *) 
     601              32 :         CPLMalloc(sizeof(int) * nBandCount );
     602              66 :     for( int ii= 0; ii < nBandCount; ii++ )
     603              34 :         panAdjustedBandList[ii] = panBandList[ii] - 1;
     604                 : 
     605                 : /* -------------------------------------------------------------------- */
     606                 : /*      Cleanup old window cache information.                           */
     607                 : /* -------------------------------------------------------------------- */
     608              32 :     CleanupWindow();
     609                 : 
     610                 : /* -------------------------------------------------------------------- */
     611                 : /*      Set the new requested window.                                   */
     612                 : /* -------------------------------------------------------------------- */
     613              32 :     CNCSError oErr;
     614                 :     
     615                 :     oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList, 
     616                 :                                 nXOff, nYOff, 
     617                 :                                 nXOff + nXSize-1, nYOff + nYSize-1,
     618              32 :                                 nBufXSize, nBufYSize );
     619                 : 
     620              32 :     CPLFree( panAdjustedBandList );
     621              32 :     if( oErr.GetErrorNumber() != NCS_SUCCESS )
     622                 :     {
     623               0 :         char* pszErrorMessage = oErr.GetErrorMessage();
     624                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     625               0 :                   "%s", pszErrorMessage );
     626               0 :         NCSFree(pszErrorMessage);
     627               0 :         bWinActive = FALSE;
     628               0 :         return CE_Failure;
     629                 :     }
     630                 : 
     631              32 :     bWinActive = TRUE;
     632                 : 
     633                 : /* -------------------------------------------------------------------- */
     634                 : /*      Record selected window.                                         */
     635                 : /* -------------------------------------------------------------------- */
     636              32 :     nWinXOff = nXOff;
     637              32 :     nWinYOff = nYOff;
     638              32 :     nWinXSize = nXSize;
     639              32 :     nWinYSize = nYSize;
     640              32 :     nWinBufXSize = nBufXSize;
     641              32 :     nWinBufYSize = nBufYSize;
     642                 : 
     643              32 :     panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
     644              32 :     memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
     645              32 :     nWinBandCount = nBandCount;
     646                 : 
     647              32 :     nWinBufLoaded = -1;
     648                 : 
     649                 : /* -------------------------------------------------------------------- */
     650                 : /*      Allocate current scanline buffer.                               */
     651                 : /* -------------------------------------------------------------------- */
     652              32 :     papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
     653              66 :     for( int iBand = 0; iBand < nWinBandCount; iBand++ )
     654              34 :         papCurLineBuf[iBand] = 
     655              34 :             CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
     656                 :         
     657              32 :     return CE_None;
     658                 : }
     659                 : 
     660                 : /************************************************************************/
     661                 : /*                           TryWinRasterIO()                           */
     662                 : /*                                                                      */
     663                 : /*      Try to satisfy the given request based on the currently         */
     664                 : /*      defined window.  Return TRUE on success or FALSE on             */
     665                 : /*      failure.  On failure, the caller should satisfy the request     */
     666                 : /*      another way (not report an error).                              */
     667                 : /************************************************************************/
     668                 : 
     669           12187 : int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag, 
     670                 :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     671                 :                                 GByte *pabyData, int nBufXSize, int nBufYSize, 
     672                 :                                 GDALDataType eDT,
     673                 :                                 int nBandCount, int *panBandList, 
     674                 :                                 int nPixelSpace, int nLineSpace, 
     675                 :                                 int nBandSpace )
     676                 : 
     677                 : {
     678                 :     int iBand, i;
     679                 : 
     680                 : /* -------------------------------------------------------------------- */
     681                 : /*      Provide default buffer organization.                            */
     682                 : /* -------------------------------------------------------------------- */
     683           12187 :     if( nPixelSpace == 0 )
     684              62 :         nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
     685           12187 :     if( nLineSpace == 0 )
     686              62 :         nLineSpace = nPixelSpace * nBufXSize;
     687           12187 :     if( nBandSpace == 0 )
     688           11785 :         nBandSpace = nLineSpace * nBufYSize;
     689                 : 
     690                 : /* -------------------------------------------------------------------- */
     691                 : /*      Do some simple tests to see if the current window can           */
     692                 : /*      satisfy our requirement.                                        */
     693                 : /* -------------------------------------------------------------------- */
     694           12187 :     if( !bWinActive )
     695              49 :         return FALSE;
     696                 :     
     697           12138 :     if( nXOff != nWinXOff || nXSize != nWinXSize )
     698               0 :         return FALSE;
     699                 : 
     700           12138 :     if( nBufXSize != nWinBufXSize )
     701               0 :         return FALSE;
     702                 : 
     703           25058 :     for( iBand = 0; iBand < nBandCount; iBand++ )
     704                 :     {
     705           12956 :         for( i = 0; i < nWinBandCount; i++ )
     706                 :         {
     707           12938 :             if( panWinBandList[iBand] == panBandList[iBand] )
     708           12920 :                 break;
     709                 :         }
     710                 : 
     711           12938 :         if( i == nWinBandCount )
     712              18 :             return FALSE;
     713                 :     }
     714                 : 
     715           12120 :     if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
     716               0 :         return FALSE;
     717                 : 
     718                 : /* -------------------------------------------------------------------- */
     719                 : /*      Now we try more subtle tests.                                   */
     720                 : /* -------------------------------------------------------------------- */
     721                 :     {
     722                 :         static int nDebugCount = 0;
     723                 : 
     724           12120 :         if( nDebugCount < 30 )
     725                 :             CPLDebug( "ECWDataset", 
     726                 :                       "TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.", 
     727              30 :                       nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     728                 : 
     729           12120 :         if( nDebugCount == 29 )
     730               1 :             CPLDebug( "ECWDataset", "No more TryWinRasterIO messages will be reported" );
     731                 :         
     732           12120 :         nDebugCount++;
     733                 :     }
     734                 : 
     735                 : /* -------------------------------------------------------------------- */
     736                 : /*      Actually load data one buffer line at a time.                   */
     737                 : /* -------------------------------------------------------------------- */
     738                 :     int iBufLine;
     739                 : 
     740           24240 :     for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
     741                 :     {
     742           12120 :         float fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
     743                 :         int iWinLine = 
     744           12120 :             (int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
     745                 :         
     746           12120 :         if( iWinLine == nWinBufLoaded + 1 )
     747           12120 :             LoadNextLine();
     748                 : 
     749           12120 :         if( iWinLine != nWinBufLoaded )
     750               0 :             return FALSE;
     751                 : 
     752                 : /* -------------------------------------------------------------------- */
     753                 : /*      Copy out all our target bands.                                  */
     754                 : /* -------------------------------------------------------------------- */
     755                 :         int iWinBand;
     756           25040 :         for( iBand = 0; iBand < nBandCount; iBand++ )
     757                 :         {
     758           14120 :             for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
     759                 :             {
     760           14120 :                 if( panWinBandList[iWinBand] == panBandList[iBand] )
     761           12920 :                     break;
     762                 :             }
     763                 : 
     764                 :             GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
     765                 :                            GDALGetDataTypeSize( eRasterDataType ) / 8, 
     766                 :                            pabyData + nBandSpace * iBand 
     767                 :                            + iBufLine * nLineSpace, eDT, nPixelSpace,
     768           12920 :                            nBufXSize );
     769                 :         }
     770                 :     }
     771                 : 
     772           12120 :     return TRUE;
     773                 : }
     774                 : 
     775                 : /************************************************************************/
     776                 : /*                            LoadNextLine()                            */
     777                 : /************************************************************************/
     778                 : 
     779           12120 : CPLErr ECWDataset::LoadNextLine()
     780                 : 
     781                 : {
     782           12120 :     if( !bWinActive )
     783               0 :         return CE_Failure;
     784                 : 
     785           12120 :     if( nWinBufLoaded == nWinBufYSize-1 )
     786                 :     {
     787               0 :         CleanupWindow();
     788               0 :         return CE_Failure;
     789                 :     }
     790                 : 
     791                 :     NCSEcwReadStatus  eRStatus;
     792                 :     eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, nWinBandCount,
     793           12120 :                                         papCurLineBuf );
     794           12120 :     if( eRStatus != NCSECW_READ_OK )
     795               0 :         return CE_Failure;
     796                 : 
     797           12120 :     nWinBufLoaded++;
     798                 : 
     799           12120 :     return CE_None;
     800                 : }
     801                 : 
     802                 : /************************************************************************/
     803                 : /*                           CleanupWindow()                            */
     804                 : /************************************************************************/
     805                 : 
     806              79 : void ECWDataset::CleanupWindow()
     807                 : 
     808                 : {
     809              79 :     if( !bWinActive )
     810              47 :         return;
     811                 : 
     812              32 :     bWinActive = FALSE;
     813              32 :     CPLFree( panWinBandList );
     814              32 :     panWinBandList = NULL;
     815                 : 
     816              66 :     for( int iBand = 0; iBand < nWinBandCount; iBand++ )
     817              34 :         CPLFree( papCurLineBuf[iBand] );
     818              32 :     CPLFree( papCurLineBuf );
     819              32 :     papCurLineBuf = NULL;
     820                 : }
     821                 : 
     822                 : /************************************************************************/
     823                 : /*                             IRasterIO()                              */
     824                 : /************************************************************************/
     825                 : 
     826             401 : CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
     827                 :                               int nXOff, int nYOff, int nXSize, int nYSize,
     828                 :                               void * pData, int nBufXSize, int nBufYSize,
     829                 :                               GDALDataType eBufType, 
     830                 :                               int nBandCount, int *panBandMap,
     831                 :                               int nPixelSpace, int nLineSpace, int nBandSpace)
     832                 :     
     833                 : {
     834                 : /* -------------------------------------------------------------------- */
     835                 : /*      Try to do it based on existing "advised" access.                */
     836                 : /* -------------------------------------------------------------------- */
     837             401 :     if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
     838                 :                         (GByte *) pData, nBufXSize, nBufYSize, 
     839                 :                         eBufType, nBandCount, panBandMap,
     840                 :                         nPixelSpace, nLineSpace, nBandSpace ) )
     841             399 :         return CE_None;
     842                 : 
     843                 : /* -------------------------------------------------------------------- */
     844                 : /*      If we are requesting a single line at 1:1, we do a multi-band   */
     845                 : /*      AdviseRead() and then TryWinRasterIO() again.                   */
     846                 : /* -------------------------------------------------------------------- */
     847               2 :     if( nYSize == 1 && nBufYSize == 1 && nBandCount > 1 )
     848                 :     {
     849                 :         CPLErr eErr;
     850                 : 
     851                 :         eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
     852                 :                            nBufXSize, GetRasterYSize() - nYOff, eBufType, 
     853               1 :                            nBandCount, panBandMap, NULL );
     854               1 :         if( eErr == CE_None 
     855                 :             && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
     856                 :                                (GByte *) pData, nBufXSize, nBufYSize, 
     857                 :                                eBufType, nBandCount, panBandMap,
     858                 :                                nPixelSpace, nLineSpace, nBandSpace ) )
     859               1 :             return CE_None;
     860                 :     }
     861                 : 
     862                 : /* -------------------------------------------------------------------- */
     863                 : /*      If we are supersampling we need to fall into the general        */
     864                 : /*      purpose logic.  We also use the general logic if we are in      */
     865                 : /*      some cases unlikely to benefit from interleaved access.         */
     866                 : /*                                                                      */
     867                 : /*      The one case we would like to handle better here is the         */
     868                 : /*      nBufYSize == 1 case (requesting a scanline at a time).  We      */
     869                 : /*      should eventually have some logic similiar to the band by       */
     870                 : /*      band case where we post a big window for the view, and allow    */
     871                 : /*      sequential reads.                                               */
     872                 : /* -------------------------------------------------------------------- */
     873               1 :     if( nXSize < nBufXSize || nYSize < nBufYSize || nYSize == 1 
     874                 :         || nBandCount > 100 || nBandCount == 1 || nBufYSize == 1 
     875                 :         || nBandCount > GetRasterCount() )
     876                 :     {
     877                 :         return 
     878                 :             GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
     879                 :                                     pData, nBufXSize, nBufYSize,
     880                 :                                     eBufType, 
     881                 :                                     nBandCount, panBandMap,
     882               0 :                                     nPixelSpace, nLineSpace, nBandSpace);
     883                 :     }
     884                 : 
     885                 :     CPLDebug( "ECWDataset", 
     886                 :               "RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.", 
     887               1 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     888                 : 
     889                 : /* -------------------------------------------------------------------- */
     890                 : /*      Setup view.                                                     */
     891                 : /* -------------------------------------------------------------------- */
     892                 :     UINT32 anBandIndices[100];
     893                 :     int    i;
     894                 :     NCSError     eNCSErr;
     895               1 :     CNCSError    oErr;
     896                 :     
     897               4 :     for( i = 0; i < nBandCount; i++ )
     898               3 :         anBandIndices[i] = panBandMap[i] - 1;
     899                 : 
     900               1 :     CleanupWindow();
     901                 : 
     902                 :     oErr = poFileView->SetView( nBandCount, anBandIndices,
     903                 :                                 nXOff, nYOff, 
     904                 :                                 nXOff + nXSize - 1, 
     905                 :                                 nYOff + nYSize - 1,
     906               1 :                                 nBufXSize, nBufYSize );
     907               1 :     eNCSErr = oErr.GetErrorNumber();
     908                 :     
     909               1 :     if( eNCSErr != NCS_SUCCESS )
     910                 :     {
     911                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     912               0 :                   "%s", NCSGetErrorText(eNCSErr) );
     913                 :         
     914               0 :         return CE_Failure;
     915                 :     }
     916                 : 
     917                 : /* -------------------------------------------------------------------- */
     918                 : /*      Setup working scanline, and the pointers into it.               */
     919                 : /* -------------------------------------------------------------------- */
     920               1 :     int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
     921                 :     GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
     922               1 :                                                  nBandCount);
     923               1 :     GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
     924                 : 
     925               4 :     for( i = 0; i < nBandCount; i++ )
     926               3 :         papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
     927                 : 
     928                 : /* -------------------------------------------------------------------- */
     929                 : /*      Read back all the data for the requested view.                  */
     930                 : /* -------------------------------------------------------------------- */
     931              41 :     for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
     932                 :     {
     933                 :         NCSEcwReadStatus  eRStatus;
     934                 : 
     935                 :         eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, nBandCount,
     936              40 :                                             (void **) papabyBIL );
     937              40 :         if( eRStatus != NCSECW_READ_OK )
     938                 :         {
     939               0 :             CPLFree( papabyBIL );
     940               0 :             CPLFree( pabyBILScanline );
     941                 :             CPLError( CE_Failure, CPLE_AppDefined,
     942               0 :                       "NCScbmReadViewLineBIL failed." );
     943               0 :             return CE_Failure;
     944                 :         }
     945                 : 
     946             160 :         for( i = 0; i < nBandCount; i++ )
     947                 :         {
     948                 :             GDALCopyWords( 
     949                 :                 pabyBILScanline + i * nDataTypeSize * nBufXSize,
     950                 :                 eRasterDataType, nDataTypeSize, 
     951                 :                 ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i, 
     952                 :                 eBufType, nPixelSpace, 
     953             120 :                 nBufXSize );
     954                 :         }
     955                 :     }
     956                 : 
     957               1 :     CPLFree( pabyBILScanline );
     958               1 :     CPLFree( papabyBIL );
     959                 : 
     960               1 :     return CE_None;
     961                 : }
     962                 : 
     963                 : /************************************************************************/
     964                 : /*                        IdentifyJPEG2000()                            */
     965                 : /*                                                                      */
     966                 : /*          Open method that only supports JPEG2000 files.              */
     967                 : /************************************************************************/
     968                 : 
     969            8674 : int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
     970                 : 
     971                 : {
     972            8674 :     if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
     973               8 :         return TRUE;
     974                 : 
     975            8666 :     else if( poOpenInfo->nHeaderBytes >= 16 
     976                 :         && (memcmp( poOpenInfo->pabyHeader, jpc_header, 
     977                 :                     sizeof(jpc_header) ) == 0
     978                 :             || memcmp( poOpenInfo->pabyHeader, jp2_header, 
     979                 :                     sizeof(jp2_header) ) == 0) )
     980              37 :         return TRUE;
     981                 :     
     982                 :     else
     983            8629 :         return FALSE;
     984                 : }
     985                 : 
     986                 : /************************************************************************/
     987                 : /*                            OpenJPEG2000()                            */
     988                 : /*                                                                      */
     989                 : /*          Open method that only supports JPEG2000 files.              */
     990                 : /************************************************************************/
     991                 : 
     992             956 : GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
     993                 : 
     994                 : {
     995             956 :     if (!IdentifyJPEG2000(poOpenInfo))
     996             914 :         return NULL;
     997                 : 
     998              42 :     return Open( poOpenInfo, TRUE );
     999                 : }
    1000                 :     
    1001                 : /************************************************************************/
    1002                 : /*                           IdentifyECW()                              */
    1003                 : /*                                                                      */
    1004                 : /*      Identify method that only supports ECW files.                   */
    1005                 : /************************************************************************/
    1006                 : 
    1007            8986 : int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
    1008                 : 
    1009                 : {
    1010                 : /* -------------------------------------------------------------------- */
    1011                 : /*      This has to either be a file on disk ending in .ecw or a        */
    1012                 : /*      ecwp: protocol url.                                             */
    1013                 : /* -------------------------------------------------------------------- */
    1014            8986 :     if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
    1015                 :          || poOpenInfo->nHeaderBytes == 0)
    1016                 :         && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5) )
    1017            8982 :         return FALSE;
    1018                 : 
    1019               4 :     return TRUE;
    1020                 : }
    1021                 : 
    1022                 : /************************************************************************/
    1023                 : /*                              OpenECW()                               */
    1024                 : /*                                                                      */
    1025                 : /*      Open method that only supports ECW files.                       */
    1026                 : /************************************************************************/
    1027                 : 
    1028            1257 : GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
    1029                 : 
    1030                 : {
    1031            1257 :     if (!IdentifyECW(poOpenInfo))
    1032            1253 :         return NULL;
    1033                 : 
    1034               4 :     return Open( poOpenInfo, FALSE );
    1035                 : }
    1036                 :     
    1037                 : /************************************************************************/
    1038                 : /*                                Open()                                */
    1039                 : /************************************************************************/
    1040                 : 
    1041              46 : GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
    1042                 : 
    1043                 : {
    1044              46 :     CNCSJP2FileView *poFileView = NULL;
    1045                 :     NCSError         eErr;
    1046              46 :     CNCSError        oErr;
    1047                 :     int              i;
    1048              46 :     FILE            *fpVSIL = NULL;
    1049              46 :     VSIIOStream *poIOStream = NULL;
    1050              46 :     int              bUsingCustomStream = FALSE;
    1051                 : 
    1052              46 :     ECWInitialize();
    1053                 : 
    1054                 : /* -------------------------------------------------------------------- */
    1055                 : /*      This will disable automatic conversion of YCbCr to RGB by       */
    1056                 : /*      the toolkit.                                                    */
    1057                 : /* -------------------------------------------------------------------- */
    1058              46 :     if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
    1059               0 :         NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
    1060                 : 
    1061                 : /* -------------------------------------------------------------------- */
    1062                 : /*      Handle special case of a JPEG2000 data stream in another file.  */
    1063                 : /* -------------------------------------------------------------------- */
    1064              46 :     int bIsVirtualFile = FALSE;
    1065                 : try_again:
    1066              68 :     if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) ||
    1067                 :         bIsVirtualFile )
    1068                 :     {
    1069              15 :         GIntBig            subfile_offset=-1, subfile_size=-1;
    1070              15 :         const char *real_filename = NULL;
    1071                 : 
    1072              15 :           if (EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12))
    1073                 :           {
    1074               5 :             char** papszTokens = CSLTokenizeString2(poOpenInfo->pszFilename + 12, ",", 0);
    1075               5 :             if (CSLCount(papszTokens) >= 2)
    1076                 :             {
    1077               5 :                 subfile_offset = CPLScanUIntBig(papszTokens[0], strlen(papszTokens[0]));
    1078               5 :                 subfile_size = CPLScanUIntBig(papszTokens[1], strlen(papszTokens[1]));
    1079                 :             }
    1080                 :             else
    1081                 :             {
    1082                 :                 CPLError( CE_Failure, CPLE_OpenFailed, 
    1083               0 :                             "Failed to parse J2K_SUBFILE specification." );
    1084               0 :                 CSLDestroy(papszTokens);
    1085               0 :                 return NULL;
    1086                 :             }
    1087               5 :             CSLDestroy(papszTokens);
    1088                 : 
    1089               5 :             real_filename = strstr(poOpenInfo->pszFilename,",");
    1090               5 :             if( real_filename != NULL )
    1091               5 :                 real_filename = strstr(real_filename+1,",");
    1092               5 :             if( real_filename != NULL )
    1093               5 :                 real_filename++;
    1094                 :             else
    1095                 :             {
    1096                 :                 CPLError( CE_Failure, CPLE_OpenFailed, 
    1097               0 :                             "Failed to parse J2K_SUBFILE specification." );
    1098               0 :                 return NULL;
    1099                 :             }
    1100                 : 
    1101                 :           }
    1102                 :           else
    1103                 :           {
    1104              10 :               real_filename = poOpenInfo->pszFilename;
    1105              10 :               subfile_offset = 0;
    1106                 :           }
    1107                 : 
    1108              15 :           fpVSIL = VSIFOpenL( real_filename, "rb" );
    1109              15 :           if( fpVSIL == NULL )
    1110                 :           {
    1111                 :               CPLError( CE_Failure, CPLE_OpenFailed, 
    1112               0 :                         "Failed to open %s.",  real_filename );
    1113               0 :               return NULL;
    1114                 :           }
    1115                 : 
    1116              15 :           if( hECWDatasetMutex == NULL )
    1117                 :           {
    1118               0 :               hECWDatasetMutex = CPLCreateMutex();
    1119                 :           }
    1120              15 :           else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
    1121                 :           {
    1122               0 :               CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
    1123                 :           }
    1124                 :           else
    1125                 :           {
    1126              15 :               CPLDebug( "ECW", "Got mutex." );
    1127                 :           }
    1128              15 :           poIOStream = new VSIIOStream();
    1129                 :           poIOStream->Access( fpVSIL, FALSE, real_filename,
    1130              30 :                               subfile_offset, subfile_size );
    1131                 : 
    1132              15 :           poFileView = new CNCSJP2FileView();
    1133              30 :           oErr = poFileView->Open( poIOStream, false );
    1134                 : 
    1135                 :           // The CNCSJP2FileView (poFileView) object may not use the iostream 
    1136                 :           // (poIOStream) passed to the CNCSJP2FileView::Open() method if an 
    1137                 :           // iostream is already available to the ECW JPEG 2000 SDK for a given
    1138                 :           // file.  Consequently, if the iostream passed to 
    1139                 :           // CNCSJP2FileView::Open() does not become the underlying iostream 
    1140                 :           // of the CNCSJP2FileView object, then it should be deleted.
    1141                 :           //
    1142                 :           // In addition, the underlying iostream of the CNCSJP2FileView object
    1143                 :           // should not be deleted until all CNCSJP2FileView objects using the 
    1144                 :           // underlying iostream are deleted. Consequently, each time a 
    1145                 :           // CNCSJP2FileView object is created, the nFileViewCount attribute 
    1146                 :           // of the underlying VSIIOStream object must be incremented for use 
    1147                 :           // in the ECWDataset destructor.
    1148                 :       
    1149                 :           VSIIOStream * poUnderlyingIOStream = 
    1150              15 :               ((VSIIOStream *)(poFileView->GetStream()));
    1151                 : 
    1152              15 :           if ( poUnderlyingIOStream )
    1153              12 :               poUnderlyingIOStream->nFileViewCount++;
    1154                 : 
    1155              15 :           if ( poIOStream != poUnderlyingIOStream ) 
    1156                 :           {
    1157               3 :               delete poIOStream;
    1158                 :           }
    1159                 :           else
    1160                 :           {
    1161              12 :               bUsingCustomStream = TRUE;
    1162                 :           }
    1163                 : 
    1164              15 :           CPLReleaseMutex( hECWDatasetMutex );
    1165                 : 
    1166              15 :           if( oErr.GetErrorNumber() != NCS_SUCCESS )
    1167                 :           {
    1168               3 :               if (poFileView)
    1169               3 :                   delete poFileView;
    1170                 : 
    1171               3 :               char* pszErrorMessage = oErr.GetErrorMessage();
    1172                 :               CPLError( CE_Failure, CPLE_AppDefined, 
    1173               3 :                         "%s", pszErrorMessage );
    1174               3 :               NCSFree(pszErrorMessage);
    1175                 : 
    1176               3 :               return NULL;
    1177                 :           }
    1178                 :     }
    1179                 : 
    1180                 : /* -------------------------------------------------------------------- */
    1181                 : /*      This has to either be a file on disk ending in .ecw or a        */
    1182                 : /*      ecwp: protocol url.                                             */
    1183                 : /* -------------------------------------------------------------------- */
    1184              41 :     else if( poOpenInfo->nHeaderBytes >= 16 
    1185                 :         && (memcmp( poOpenInfo->pabyHeader, jpc_header, 
    1186                 :                     sizeof(jpc_header) ) == 0
    1187                 :             || memcmp( poOpenInfo->pabyHeader, jp2_header, 
    1188                 :                     sizeof(jp2_header) ) == 0) )
    1189                 :     {
    1190                 :         /* accept JPEG2000 files */
    1191                 :     }
    1192               4 :     else if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
    1193                 :               || poOpenInfo->nHeaderBytes == 0)
    1194                 :              && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5) )
    1195               0 :         return( NULL );
    1196                 :     
    1197                 : /* -------------------------------------------------------------------- */
    1198                 : /*      Open the client interface.                                      */
    1199                 : /* -------------------------------------------------------------------- */
    1200              53 :     if( poFileView == NULL )
    1201                 :     {
    1202              41 :         poFileView = new CNCSFile();
    1203              82 :         oErr = poFileView->Open( (char *) poOpenInfo->pszFilename, FALSE );
    1204              41 :         eErr = oErr.GetErrorNumber();
    1205                 :         CPLDebug( "ECW", "NCScbmOpenFileView(%s): eErr = %d", 
    1206              41 :                   poOpenInfo->pszFilename, (int) eErr );
    1207              41 :         if( eErr != NCS_SUCCESS )
    1208                 :         {
    1209              10 :             delete poFileView;
    1210                 : 
    1211                 :             /* If the file is not a 'real' file but recognized as a */
    1212                 :             /* virtual file by the VSIL API, try again by using a */
    1213                 :             /* VSIIOStream object, like in the J2K_SUBFILE case */
    1214                 :             VSIStatBuf sBuf;
    1215                 :             VSIStatBufL sBufL;
    1216              10 :             if (!bIsVirtualFile &&
    1217                 :                 VSIStat(poOpenInfo->pszFilename, &sBuf) != 0 &&
    1218                 :                 VSIStatL(poOpenInfo->pszFilename, &sBufL) == 0)
    1219                 :             {
    1220              10 :                 bIsVirtualFile = TRUE;
    1221              10 :                 goto try_again;
    1222                 :             }
    1223                 : 
    1224                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1225               0 :                       "%s", NCSGetErrorText(eErr) );
    1226               0 :             return NULL;
    1227                 :         }
    1228                 :     }
    1229                 : 
    1230              43 :     if( poOpenInfo->eAccess == GA_Update )
    1231                 :     {
    1232                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1233                 :                   "The DIMAP driver does not support update access to existing"
    1234               0 :                   " datasets.\n" );
    1235               0 :         return NULL;
    1236                 :     }
    1237                 :     
    1238                 : /* -------------------------------------------------------------------- */
    1239                 : /*      Create a corresponding GDALDataset.                             */
    1240                 : /* -------------------------------------------------------------------- */
    1241                 :     ECWDataset  *poDS;
    1242                 : 
    1243              43 :     poDS = new ECWDataset(bIsJPEG2000);
    1244                 : 
    1245              43 :     poDS->poFileView = poFileView;
    1246                 : 
    1247              43 :     if( fpVSIL != NULL )
    1248              12 :         poDS->nPamFlags |= GPF_DISABLED;
    1249                 : 
    1250              43 :     poDS->bUsingCustomStream = bUsingCustomStream;
    1251                 : 
    1252                 : /* -------------------------------------------------------------------- */
    1253                 : /*      Fetch general file information.                                 */
    1254                 : /* -------------------------------------------------------------------- */
    1255              43 :     poDS->psFileInfo = poFileView->GetFileInfo();
    1256                 : 
    1257                 :     CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
    1258                 :               "       OriginXY=%g,%g  CellIncrementXY=%g,%g\n",
    1259                 :               poDS->psFileInfo->nSizeX,
    1260                 :               poDS->psFileInfo->nSizeY,
    1261                 :               poDS->psFileInfo->nBands,
    1262                 :               poDS->psFileInfo->fOriginX,
    1263                 :               poDS->psFileInfo->fOriginY,
    1264                 :               poDS->psFileInfo->fCellIncrementX,
    1265              43 :               poDS->psFileInfo->fCellIncrementY );
    1266                 : 
    1267                 : /* -------------------------------------------------------------------- */
    1268                 : /*      Establish raster info.                                          */
    1269                 : /* -------------------------------------------------------------------- */
    1270              43 :     poDS->nRasterXSize = poDS->psFileInfo->nSizeX; 
    1271              43 :     poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
    1272                 : 
    1273                 : /* -------------------------------------------------------------------- */
    1274                 : /*      Establish the GDAL data type that corresponds.  A few NCS       */
    1275                 : /*      data types have no direct corresponding value in GDAL so we     */
    1276                 : /*      will coerce to something sufficiently similar.                  */
    1277                 : /* -------------------------------------------------------------------- */
    1278              43 :     poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
    1279              43 :     switch( poDS->psFileInfo->eCellType )
    1280                 :     {
    1281                 :         case NCSCT_UINT8:
    1282              32 :             poDS->eRasterDataType = GDT_Byte;
    1283              32 :             break;
    1284                 : 
    1285                 :         case NCSCT_UINT16:
    1286               5 :             poDS->eRasterDataType = GDT_UInt16;
    1287               5 :             break;
    1288                 : 
    1289                 :         case NCSCT_UINT32:
    1290                 :         case NCSCT_UINT64:
    1291               1 :             poDS->eRasterDataType = GDT_UInt32;
    1292               1 :             poDS->eNCSRequestDataType = NCSCT_UINT32;
    1293               1 :             break;
    1294                 : 
    1295                 :         case NCSCT_INT8:
    1296                 :         case NCSCT_INT16:
    1297               3 :             poDS->eRasterDataType = GDT_Int16;
    1298               3 :             poDS->eNCSRequestDataType = NCSCT_INT16;
    1299               3 :             break;
    1300                 : 
    1301                 :         case NCSCT_INT32:
    1302                 :         case NCSCT_INT64:
    1303               2 :             poDS->eRasterDataType = GDT_Int32;
    1304               2 :             poDS->eNCSRequestDataType = NCSCT_INT32;
    1305               2 :             break;
    1306                 : 
    1307                 :         case NCSCT_IEEE4:
    1308               0 :             poDS->eRasterDataType = GDT_Float32;
    1309               0 :             break;
    1310                 : 
    1311                 :         case NCSCT_IEEE8:
    1312               0 :             poDS->eRasterDataType = GDT_Float64;
    1313                 :             break;
    1314                 :     }
    1315                 : 
    1316                 : /* -------------------------------------------------------------------- */
    1317                 : /*      Create band information objects.                                */
    1318                 : /* -------------------------------------------------------------------- */
    1319             134 :     for( i=0; i < poDS->psFileInfo->nBands; i++ )
    1320              91 :         poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
    1321                 : 
    1322                 : /* -------------------------------------------------------------------- */
    1323                 : /*      Look for supporting coordinate system information.              */
    1324                 : /* -------------------------------------------------------------------- */
    1325              43 :     GDALJP2Metadata oJP2Geo;
    1326                 : 
    1327              43 :     if( oJP2Geo.ReadAndParse( poOpenInfo->pszFilename ) )
    1328                 :     {
    1329              22 :         poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
    1330              22 :         poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
    1331                 :         memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform, 
    1332              22 :                 sizeof(double) * 6 );
    1333              22 :         poDS->nGCPCount = oJP2Geo.nGCPCount;
    1334              22 :         poDS->pasGCPList = oJP2Geo.pasGCPList;
    1335              22 :         oJP2Geo.pasGCPList = NULL;
    1336              22 :         oJP2Geo.nGCPCount = 0;
    1337                 :     }
    1338                 :     else
    1339                 :     {
    1340              21 :         poDS->ECW2WKTProjection();
    1341                 :     }
    1342                 : 
    1343                 : /* -------------------------------------------------------------------- */
    1344                 : /*      Check for world file for ecw files.                             */
    1345                 : /* -------------------------------------------------------------------- */
    1346              43 :     if( !poDS->bGeoTransformValid 
    1347                 :         && EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw") )
    1348                 :     {
    1349                 :         poDS->bGeoTransformValid |= 
    1350                 :             GDALReadWorldFile( poOpenInfo->pszFilename, ".eww", 
    1351                 :                                poDS->adfGeoTransform )
    1352                 :             || GDALReadWorldFile( poOpenInfo->pszFilename, ".ecww", 
    1353                 :                                   poDS->adfGeoTransform )
    1354                 :             || GDALReadWorldFile( poOpenInfo->pszFilename, ".wld", 
    1355               0 :                                   poDS->adfGeoTransform );
    1356                 :     }
    1357                 : 
    1358                 : /* -------------------------------------------------------------------- */
    1359                 : /*      Initialize any PAM information.                                 */
    1360                 : /* -------------------------------------------------------------------- */
    1361              43 :     poDS->SetDescription( poOpenInfo->pszFilename );
    1362              43 :     poDS->TryLoadXML();
    1363                 :     
    1364                 : /* -------------------------------------------------------------------- */
    1365                 : /*      Confirm the requested access is supported.                      */
    1366                 : /* -------------------------------------------------------------------- */
    1367              43 :     if( poOpenInfo->eAccess == GA_Update )
    1368                 :     {
    1369               0 :         delete poDS;
    1370                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    1371                 :                   "The ECW driver does not support update access to existing"
    1372               0 :                   " datasets.\n" );
    1373               0 :         return NULL;
    1374                 :     }
    1375                 :     
    1376              43 :     return( poDS );
    1377                 : }
    1378                 : 
    1379                 : /************************************************************************/
    1380                 : /*                            GetGCPCount()                             */
    1381                 : /************************************************************************/
    1382                 : 
    1383               6 : int ECWDataset::GetGCPCount()
    1384                 : 
    1385                 : {
    1386               6 :     if( nGCPCount != 0 )
    1387               3 :         return nGCPCount;
    1388                 :     else
    1389               3 :         return GDALPamDataset::GetGCPCount();
    1390                 : }
    1391                 : 
    1392                 : /************************************************************************/
    1393                 : /*                          GetGCPProjection()                          */
    1394                 : /************************************************************************/
    1395                 : 
    1396               2 : const char *ECWDataset::GetGCPProjection()
    1397                 : 
    1398                 : {
    1399               2 :     if( nGCPCount > 0 )
    1400               2 :         return pszProjection;
    1401                 :     else
    1402               0 :         return GDALPamDataset::GetGCPProjection();
    1403                 : }
    1404                 : 
    1405                 : /************************************************************************/
    1406                 : /*                               GetGCP()                               */
    1407                 : /************************************************************************/
    1408                 : 
    1409               3 : const GDAL_GCP *ECWDataset::GetGCPs()
    1410                 : 
    1411                 : {
    1412               3 :     if( nGCPCount != 0 )
    1413               2 :         return pasGCPList;
    1414                 :     else
    1415               1 :         return GDALPamDataset::GetGCPs();
    1416                 : }
    1417                 : 
    1418                 : /************************************************************************/
    1419                 : /*                          GetProjectionRef()                          */
    1420                 : /*                                                                      */
    1421                 : /*      We let PAM coordinate system override the one stored inside     */
    1422                 : /*      our file.                                                       */
    1423                 : /************************************************************************/
    1424                 : 
    1425              60 : const char *ECWDataset::GetProjectionRef() 
    1426                 : 
    1427                 : {
    1428              60 :     const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
    1429                 : 
    1430              60 :     if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
    1431              40 :         return pszProjection;
    1432                 :     else
    1433              20 :         return pszPamPrj;
    1434                 : }
    1435                 : 
    1436                 : /************************************************************************/
    1437                 : /*                          GetGeoTransform()                           */
    1438                 : /*                                                                      */
    1439                 : /*      Only return the native geotransform if we appear to be          */
    1440                 : /*      returning the native coordinate system, otherwise defer to      */
    1441                 : /*      the PAM geotransform.                                           */
    1442                 : /************************************************************************/
    1443                 : 
    1444              22 : CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
    1445                 : 
    1446                 : {
    1447              29 :     if( (GetProjectionRef() != pszProjection  
    1448               7 :          && strlen(GetProjectionRef()) > 0)
    1449                 :         || !bGeoTransformValid )
    1450                 :     {
    1451               2 :         return GDALPamDataset::GetGeoTransform( padfTransform );
    1452                 :     }
    1453                 :     else
    1454                 :     {
    1455              20 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1456              20 :         return( CE_None );
    1457                 :     }
    1458                 : }
    1459                 : 
    1460                 : /************************************************************************/
    1461                 : /*                            GetMetadata()                             */
    1462                 : /************************************************************************/
    1463                 : 
    1464              13 : char **ECWDataset::GetMetadata( const char *pszDomain )
    1465                 : 
    1466                 : {
    1467              13 :     if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
    1468              13 :         return GDALPamDataset::GetMetadata( pszDomain );
    1469                 :     else
    1470               0 :         return papszGMLMetadata;
    1471                 : }
    1472                 : 
    1473                 : /************************************************************************/
    1474                 : /*                         ECW2WKTProjection()                          */
    1475                 : /*                                                                      */
    1476                 : /*      Set the dataset pszProjection string in OGC WKT format by       */
    1477                 : /*      looking up the ECW (GDT) coordinate system info in              */
    1478                 : /*      ecw_cs.dat support data file.                                   */
    1479                 : /*                                                                      */
    1480                 : /*      This code is likely still broken in some circumstances.  For    */
    1481                 : /*      instance, I haven't been careful about changing the linear      */
    1482                 : /*      projection parameters (false easting/northing) if the units     */
    1483                 : /*      is feet.  Lots of cases missing here, and in ecw_cs.dat.        */
    1484                 : /************************************************************************/
    1485                 : 
    1486              21 : void ECWDataset::ECW2WKTProjection()
    1487                 : 
    1488                 : {
    1489              21 :     if( psFileInfo == NULL )
    1490               0 :         return;
    1491                 : 
    1492                 : /* -------------------------------------------------------------------- */
    1493                 : /*      Capture Geotransform.                                           */
    1494                 : /*                                                                      */
    1495                 : /*      We will try to ignore the provided file information if it is    */
    1496                 : /*      origin (0,0) and pixel size (1,1).  I think sometimes I have    */
    1497                 : /*      also seen pixel increments of 0 on invalid datasets.            */
    1498                 : /* -------------------------------------------------------------------- */
    1499              21 :     if( psFileInfo->fOriginX != 0.0 
    1500                 :         || psFileInfo->fOriginY != 0.0 
    1501                 :         || (psFileInfo->fCellIncrementX != 0.0 
    1502                 :             && psFileInfo->fCellIncrementX != 1.0)
    1503                 :         || (psFileInfo->fCellIncrementY != 0.0 
    1504                 :             && psFileInfo->fCellIncrementY != 1.0) )
    1505                 :     {
    1506               4 :         bGeoTransformValid = TRUE;
    1507                 :         
    1508               4 :         adfGeoTransform[0] = psFileInfo->fOriginX;
    1509               4 :         adfGeoTransform[1] = psFileInfo->fCellIncrementX;
    1510               4 :         adfGeoTransform[2] = 0.0;
    1511                 :         
    1512               4 :         adfGeoTransform[3] = psFileInfo->fOriginY;
    1513               4 :         adfGeoTransform[4] = 0.0;
    1514               4 :         adfGeoTransform[5] = psFileInfo->fCellIncrementY;
    1515                 :     }
    1516                 : 
    1517                 : /* -------------------------------------------------------------------- */
    1518                 : /*      do we have projection and datum?                                */
    1519                 : /* -------------------------------------------------------------------- */
    1520                 :     CPLDebug( "ECW", "projection=%s, datum=%s",
    1521              21 :               psFileInfo->szProjection, psFileInfo->szDatum );
    1522                 : 
    1523              21 :     if( EQUAL(psFileInfo->szProjection,"RAW") )
    1524              21 :         return;
    1525                 : 
    1526                 : /* -------------------------------------------------------------------- */
    1527                 : /*      Set projection if we have it.                                   */
    1528                 : /* -------------------------------------------------------------------- */
    1529               0 :     OGRSpatialReference oSRS;
    1530               0 :     CPLString osUnits = "METERS";
    1531                 : 
    1532               0 :     if( psFileInfo->eCellSizeUnits == ECW_CELL_UNITS_FEET )
    1533               0 :         osUnits = "FEET";
    1534                 : 
    1535               0 :     if( oSRS.importFromERM( psFileInfo->szProjection, 
    1536                 :                             psFileInfo->szDatum, 
    1537                 :                             osUnits ) != OGRERR_NONE )
    1538                 :         return;
    1539                 : 
    1540               0 :     oSRS.exportToWkt( &pszProjection );
    1541                 : }
    1542                 : 
    1543                 : #endif /* def FRMT_ecw */
    1544                 : 
    1545                 : /************************************************************************/
    1546                 : /*                           ECWInitialize()                            */
    1547                 : /*                                                                      */
    1548                 : /*      Initialize NCS library.  We try to defer this as late as        */
    1549                 : /*      possible since de-initializing it seems to be expensive/slow    */
    1550                 : /*      on some system.                                                 */
    1551                 : /************************************************************************/
    1552                 : 
    1553              79 : void ECWInitialize()
    1554                 : 
    1555                 : {
    1556              79 :     CPLMutexHolder oHolder( &hECWDatasetMutex );
    1557                 : 
    1558              79 :     if( bNCSInitialized )
    1559                 :         return;
    1560                 : 
    1561               1 :     NCSecwInit();
    1562               1 :     bNCSInitialized = TRUE;
    1563                 : 
    1564                 :     const char *pszEcwCacheSize = 
    1565               1 :         CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
    1566                 : 
    1567               1 :     if( pszEcwCacheSize != NULL )
    1568               0 :         NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, atoi(pszEcwCacheSize) );
    1569                 : }
    1570                 : 
    1571                 : /************************************************************************/
    1572                 : /*                         GDALDeregister_ECW()                         */
    1573                 : /************************************************************************/
    1574                 : 
    1575             325 : void GDALDeregister_ECW( GDALDriver * )
    1576                 : 
    1577                 : {
    1578                 :     /* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
    1579                 :     /* Not worth it */
    1580                 : #ifdef notdef
    1581                 :     if( bNCSInitialized )
    1582                 :     {
    1583                 :         bNCSInitialized = FALSE;
    1584                 :         NCSecwShutdown();
    1585                 :     }
    1586                 : 
    1587                 :     if( hECWDatasetMutex != NULL )
    1588                 :     {
    1589                 :         CPLDestroyMutex( hECWDatasetMutex );
    1590                 :         hECWDatasetMutex = NULL;
    1591                 :     }
    1592                 : #endif
    1593             325 : }
    1594                 : 
    1595                 : /************************************************************************/
    1596                 : /*                          GDALRegister_ECW()                        */
    1597                 : /************************************************************************/
    1598                 : 
    1599             338 : void GDALRegister_ECW()
    1600                 : 
    1601                 : {
    1602                 : #ifdef FRMT_ecw 
    1603                 :     GDALDriver  *poDriver;
    1604                 : 
    1605             338 :     if (! GDAL_CHECK_VERSION("ECW driver"))
    1606               0 :         return;
    1607                 : 
    1608             338 :     if( GDALGetDriverByName( "ECW" ) == NULL )
    1609                 :     {
    1610             336 :         poDriver = new GDALDriver();
    1611                 :         
    1612             336 :         poDriver->SetDescription( "ECW" );
    1613                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1614             336 :                                    "ERMapper Compressed Wavelets" );
    1615                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1616             336 :                                    "frmt_ecw.html" );
    1617             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
    1618                 :         
    1619             336 :         poDriver->pfnIdentify = ECWDataset::IdentifyECW;
    1620             336 :         poDriver->pfnOpen = ECWDataset::OpenECW;
    1621             336 :         poDriver->pfnUnloadDriver = GDALDeregister_ECW;
    1622                 : #ifdef HAVE_COMPRESS
    1623                 : // The create method seems not to work properly.
    1624                 : //        poDriver->pfnCreate = ECWCreateECW;  
    1625             336 :         poDriver->pfnCreateCopy = ECWCreateCopyECW;
    1626                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    1627             336 :                                    "Byte" );
    1628                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    1629                 : "<CreationOptionList>"
    1630                 : "   <Option name='TARGET' type='float' description='Compression Percentage' />"
    1631                 : "   <Option name='PROJ' type='string' description='ERMapper Projection Name'/>"
    1632                 : "   <Option name='DATUM' type='string' description='ERMapper Datum Name' />"
    1633                 : "   <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
    1634             336 : "</CreationOptionList>" );
    1635                 : #endif
    1636                 : 
    1637             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1638                 :     }
    1639                 : #endif /* def FRMT_ecw */
    1640                 : }
    1641                 : 
    1642                 : /************************************************************************/
    1643                 : /*                      GDALRegister_ECW_JP2ECW()                       */
    1644                 : /*                                                                      */
    1645                 : /*      This function exists so that when built as a plugin, there      */
    1646                 : /*      is a function that will register both drivers.                  */
    1647                 : /************************************************************************/
    1648                 : 
    1649               0 : void GDALRegister_ECW_JP2ECW()
    1650                 : 
    1651                 : {
    1652               0 :     GDALRegister_ECW();
    1653               0 :     GDALRegister_JP2ECW();
    1654               0 : }
    1655                 : 
    1656                 : /************************************************************************/
    1657                 : /*                     ECWDatasetOpenJPEG2000()                         */
    1658                 : /************************************************************************/
    1659              14 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
    1660                 : {
    1661              14 :     return ECWDataset::OpenJPEG2000(poOpenInfo);
    1662                 : }
    1663                 : 
    1664                 : /************************************************************************/
    1665                 : /*                        GDALRegister_JP2ECW()                         */
    1666                 : /************************************************************************/
    1667             338 : void GDALRegister_JP2ECW()
    1668                 : 
    1669                 : {
    1670                 : #ifdef FRMT_ecw 
    1671                 :     GDALDriver  *poDriver;
    1672                 : 
    1673             338 :     if (! GDAL_CHECK_VERSION("JP2ECW driver"))
    1674               0 :         return;
    1675                 : 
    1676             338 :     if( GDALGetDriverByName( "JP2ECW" ) == NULL )
    1677                 :     {
    1678             336 :         poDriver = new GDALDriver();
    1679                 :         
    1680             336 :         poDriver->SetDescription( "JP2ECW" );
    1681                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    1682             336 :                                    "ERMapper JPEG2000" );
    1683                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    1684             336 :                                    "frmt_jp2ecw.html" );
    1685             336 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
    1686                 :         
    1687             336 :         poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
    1688             336 :         poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
    1689                 : #ifdef HAVE_COMPRESS
    1690             336 :         poDriver->pfnCreate = ECWCreateJPEG2000;
    1691             336 :         poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
    1692                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    1693             336 :                                    "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
    1694                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    1695                 : "<CreationOptionList>"
    1696                 : "   <Option name='TARGET' type='float' description='Compression Percentage' />"
    1697                 : "   <Option name='PROJ' type='string' description='ERMapper Projection Name'/>"
    1698                 : "   <Option name='DATUM' type='string' description='ERMapper Datum Name' />"
    1699                 : "   <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
    1700                 : "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
    1701                 : "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
    1702                 : "   <Option name='PROFILE' type='string-select'>"
    1703                 : "       <Value>BASELINE_0</Value>"
    1704                 : "       <Value>BASELINE_1</Value>"
    1705                 : "       <Value>BASELINE_2</Value>"
    1706                 : "       <Value>NPJE</Value>"
    1707                 : "       <Value>EPJE</Value>"
    1708                 : "   </Option>"
    1709                 : "   <Option name='PROGRESSION' type='string-select'>"
    1710                 : "       <Value>LRCP</Value>"
    1711                 : "       <Value>RLCP</Value>"
    1712                 : "       <Value>RPCL</Value>"
    1713                 : "   </Option>"
    1714                 : "   <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
    1715                 : "   <Option name='LEVELS' type='int'/>"
    1716                 : "   <Option name='LAYERS' type='int'/>"
    1717                 : "   <Option name='PRECINCT_WIDTH' type='int'/>"
    1718                 : "   <Option name='PRECINCT_HEIGHT' type='int'/>"
    1719                 : "   <Option name='TILE_WIDTH' type='int'/>"
    1720                 : "   <Option name='TILE_HEIGHT' type='int'/>"
    1721                 : "   <Option name='INCLUDE_SOP' type='boolean'/>"
    1722                 : "   <Option name='INCLUDE_EPH' type='boolean'/>"
    1723                 : "   <Option name='DECOMPRESS_LAYERS' type='int'/>"
    1724                 : "   <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
    1725             336 : "</CreationOptionList>" );
    1726                 : #endif
    1727                 : 
    1728             336 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    1729                 :     }
    1730                 : #endif /* def FRMT_ecw */
    1731            1140 : }
    1732                 : 
    1733                 : 
    1734                 : 
    1735                 : 

Generated by: LCOV version 1.7