LCOV - code coverage report
Current view: directory - frmts/ecw - ecwdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 744 604 81.2 %
Date: 2012-04-28 Functions: 52 43 82.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ecwdataset.cpp 23321 2011-11-05 13:20:20Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL 
       5                 :  * Purpose:  ECW (ERDAS 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_ecw.h"
      31                 : #include "cpl_minixml.h"
      32                 : #include "ogr_spatialref.h"
      33                 : #include "ogr_api.h"
      34                 : #include "ogr_geometry.h"
      35                 : 
      36                 : CPL_CVSID("$Id: ecwdataset.cpp 23321 2011-11-05 13:20:20Z rouault $");
      37                 : 
      38                 : #undef NOISY_DEBUG
      39                 : 
      40                 : #ifdef FRMT_ecw
      41                 : 
      42                 : static const unsigned char jpc_header[] = {0xff,0x4f};
      43                 : static const unsigned char jp2_header[] = 
      44                 :     {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
      45                 : 
      46                 : static void *hECWDatasetMutex = NULL;
      47                 : static int    bNCSInitialized = FALSE;
      48                 : 
      49                 : void ECWInitialize( void );
      50                 : 
      51                 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo);
      52                 : 
      53                 : /************************************************************************/
      54                 : /*                           ECWRasterBand()                            */
      55                 : /************************************************************************/
      56                 : 
      57             386 : ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
      58                 : 
      59                 : {
      60             386 :     this->poDS = poDS;
      61             386 :     poGDS = poDS;
      62                 : 
      63             386 :     this->iOverview = iOverview;
      64             386 :     this->nBand = nBand;
      65             386 :     eDataType = poDS->eRasterDataType;
      66                 : 
      67             386 :     nRasterXSize = poDS->GetRasterXSize() / ( 1 << (iOverview+1));
      68             386 :     nRasterYSize = poDS->GetRasterYSize() / ( 1 << (iOverview+1));
      69                 : 
      70             386 :     nBlockXSize = nRasterXSize;
      71             386 :     nBlockYSize = 1;
      72                 : 
      73                 : /* -------------------------------------------------------------------- */
      74                 : /*      Work out band color interpretation.                             */
      75                 : /* -------------------------------------------------------------------- */
      76             386 :     if( poDS->psFileInfo->eColorSpace == NCSCS_NONE )
      77               0 :         eBandInterp = GCI_Undefined;
      78             386 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_GREYSCALE )
      79              70 :         eBandInterp = GCI_GrayIndex;
      80             316 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND )
      81              56 :         eBandInterp = GCI_Undefined;
      82             260 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_sRGB )
      83                 :     {
      84             260 :         if( nBand == 1 )
      85              86 :             eBandInterp = GCI_RedBand;
      86             174 :         else if( nBand == 2 )
      87              86 :             eBandInterp = GCI_GreenBand;
      88              88 :         else if( nBand == 3 )
      89              86 :             eBandInterp = GCI_BlueBand;
      90               2 :         else if( nBand == 4 )
      91               2 :             eBandInterp = GCI_AlphaBand;
      92                 :         else
      93               0 :             eBandInterp = GCI_Undefined;
      94                 :     }
      95               0 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
      96                 :     {
      97               0 :         if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
      98                 :         {
      99               0 :             if( nBand == 1 )
     100               0 :                 eBandInterp = GCI_RedBand;
     101               0 :             else if( nBand == 2 )
     102               0 :                 eBandInterp = GCI_GreenBand;
     103               0 :             else if( nBand == 3 )
     104               0 :                 eBandInterp = GCI_BlueBand;
     105                 :             else
     106               0 :                 eBandInterp = GCI_Undefined;
     107                 :         }
     108                 :         else
     109                 :         {
     110               0 :             if( nBand == 1 )
     111               0 :                 eBandInterp = GCI_YCbCr_YBand;
     112               0 :             else if( nBand == 2 )
     113               0 :                 eBandInterp = GCI_YCbCr_CbBand;
     114               0 :             else if( nBand == 3 )
     115               0 :                 eBandInterp = GCI_YCbCr_CrBand;
     116                 :             else
     117               0 :                 eBandInterp = GCI_Undefined;
     118                 :         }
     119                 :     }
     120                 :     else
     121               0 :         eBandInterp = GCI_Undefined;
     122                 : 
     123                 : /* -------------------------------------------------------------------- */
     124                 : /*      If this is the base level, create a set of overviews.           */
     125                 : /* -------------------------------------------------------------------- */
     126             386 :     if( iOverview == -1 )
     127                 :     {
     128                 :         int i;
     129             386 :         for( i = 0; 
     130                 :              nRasterXSize / (1 << (i+1)) > 128 
     131                 :                  && nRasterYSize / (1 << (i+1)) > 128;
     132                 :              i++ )
     133                 :         {
     134             156 :             apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i ) );
     135                 :         }
     136                 :     }
     137                 : 
     138             386 :     if( (poDS->psFileInfo->pBands[nBand-1].nBits % 8) != 0 )
     139                 :         SetMetadataItem("NBITS",
     140               8 :                         CPLString().Printf("%d",poDS->psFileInfo->pBands[nBand-1].nBits),
     141               8 :                         "IMAGE_STRUCTURE" );
     142             386 : }
     143                 : 
     144                 : /************************************************************************/
     145                 : /*                          ~ECWRasterBand()                           */
     146                 : /************************************************************************/
     147                 : 
     148             386 : ECWRasterBand::~ECWRasterBand()
     149                 : 
     150                 : {
     151             386 :     FlushCache();
     152                 : 
     153             928 :     while( apoOverviews.size() > 0 )
     154                 :     {
     155             156 :         delete apoOverviews.back();
     156             156 :         apoOverviews.pop_back();
     157                 :     }
     158             386 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                            GetOverview()                             */
     162                 : /************************************************************************/
     163                 : 
     164               2 : GDALRasterBand *ECWRasterBand::GetOverview( int iOverview )
     165                 : 
     166                 : {
     167               2 :     if( iOverview >= 0 && iOverview < (int) apoOverviews.size() )
     168               2 :         return apoOverviews[iOverview];
     169                 :     else
     170               0 :         return NULL;
     171                 : }
     172                 : 
     173                 : /************************************************************************/
     174                 : /*                       GetColorInterpretation()                       */
     175                 : /************************************************************************/
     176                 : 
     177             122 : GDALColorInterp ECWRasterBand::GetColorInterpretation()
     178                 : 
     179                 : {
     180             122 :     return eBandInterp;
     181                 : }
     182                 : 
     183                 : /************************************************************************/
     184                 : /*                       SetColorInterpretation()                       */
     185                 : /*                                                                      */
     186                 : /*      This would normally just be used by folks using the ECW code    */
     187                 : /*      to read JP2 streams in other formats (such as NITF) and         */
     188                 : /*      providing their own color interpretation regardless of what     */
     189                 : /*      ECW might think the stream itself says.                         */
     190                 : /************************************************************************/
     191                 : 
     192               0 : CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
     193                 : 
     194                 : {
     195               0 :     eBandInterp = eNewInterp;
     196                 : 
     197               0 :     return CE_None;
     198                 : }
     199                 : 
     200                 : /************************************************************************/
     201                 : /*                             AdviseRead()                             */
     202                 : /************************************************************************/
     203                 : 
     204              62 : CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     205                 :                                   int nBufXSize, int nBufYSize, 
     206                 :                                   GDALDataType eDT, 
     207                 :                                   char **papszOptions )
     208                 : {
     209              62 :     int nResFactor = 1 << (iOverview+1);
     210                 :     
     211                 :     return poGDS->AdviseRead( nXOff * nResFactor, 
     212                 :                               nYOff * nResFactor, 
     213                 :                               nXSize * nResFactor, 
     214                 :                               nYSize * nResFactor, 
     215                 :                               nBufXSize, nBufYSize, eDT, 
     216              62 :                               1, &nBand, papszOptions );
     217                 : }
     218                 : 
     219                 : /************************************************************************/
     220                 : /*                             IRasterIO()                              */
     221                 : /************************************************************************/
     222                 : 
     223           25450 : CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     224                 :                                  int nXOff, int nYOff, int nXSize, int nYSize,
     225                 :                                  void * pData, int nBufXSize, int nBufYSize,
     226                 :                                  GDALDataType eBufType,
     227                 :                                  int nPixelSpace, int nLineSpace )
     228                 :     
     229                 : {
     230                 :     int          iBand, bDirect;
     231           25450 :     GByte        *pabyWorkBuffer = NULL;
     232           25450 :     int nResFactor = 1 << (iOverview+1);
     233                 : 
     234                 : /* -------------------------------------------------------------------- */
     235                 : /*      Try to do it based on existing "advised" access.                */
     236                 : /* -------------------------------------------------------------------- */
     237           25450 :     if( poGDS->TryWinRasterIO( eRWFlag, 
     238                 :                                nXOff * nResFactor, nYOff * nResFactor, 
     239                 :                                nXSize * nResFactor, nYSize * nResFactor, 
     240                 :                                (GByte *) pData, nBufXSize, nBufYSize, 
     241                 :                                eBufType, 1, &nBand, 
     242                 :                                nPixelSpace, nLineSpace, 0 ) )
     243           25382 :         return CE_None;
     244                 : 
     245                 : /* -------------------------------------------------------------------- */
     246                 : /*      We will drop down to the block oriented API if only a single    */
     247                 : /*      scanline was requested. This is based on the assumption that    */
     248                 : /*      doing lots of single scanline windows is expensive.             */
     249                 : /* -------------------------------------------------------------------- */
     250              68 :     if( nYSize == 1 )
     251                 :     {
     252                 : #ifdef NOISY_DEBUG
     253                 :         CPLDebug( "ECWRasterBand", 
     254                 :                   "RasterIO(%d,%d,%d,%d -> %dx%d) - redirected.", 
     255                 :                   nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     256                 : #endif
     257                 :         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     258                 :                                          pData, nBufXSize, nBufYSize, 
     259              62 :                                          eBufType, nPixelSpace, nLineSpace );
     260                 :     }
     261                 : 
     262                 : /* -------------------------------------------------------------------- */
     263                 : /*      The ECW SDK doesn't supersample, so adjust for this case.       */
     264                 : /* -------------------------------------------------------------------- */
     265                 :     CPLDebug( "ECWRasterBand", 
     266                 :               "RasterIO(nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)", 
     267               6 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     268                 : 
     269               6 :     nXOff *= nResFactor;
     270               6 :     nYOff *= nResFactor;
     271               6 :     nXSize *= nResFactor;
     272               6 :     nYSize *= nResFactor;
     273                 : 
     274               6 :     int          nNewXSize = nBufXSize, nNewYSize = nBufYSize;
     275                 : 
     276               6 :     if ( nXSize < nBufXSize )
     277               0 :         nNewXSize = nXSize;
     278                 : 
     279               6 :     if ( nYSize < nBufYSize )
     280               0 :         nNewYSize = nYSize;
     281                 : 
     282                 : /* -------------------------------------------------------------------- */
     283                 : /*      Default line and pixel spacing if needed.                       */
     284                 : /* -------------------------------------------------------------------- */
     285               6 :     if ( nPixelSpace == 0 )
     286               0 :         nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
     287                 : 
     288               6 :     if ( nLineSpace == 0 )
     289               0 :         nLineSpace = nPixelSpace * nBufXSize;
     290                 : 
     291                 : /* -------------------------------------------------------------------- */
     292                 : /*      Can we perform direct loads, or must we load into a working     */
     293                 : /*      buffer, and transform?                                          */
     294                 : /* -------------------------------------------------------------------- */
     295               6 :     int     nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
     296                 : 
     297                 :     bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
     298               6 :       && nNewXSize == nBufXSize && nNewYSize == nBufYSize;
     299               6 :     if( !bDirect )
     300               2 :         pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
     301                 : 
     302                 : /* -------------------------------------------------------------------- */
     303                 : /*      Establish access at the desired resolution.                     */
     304                 : /* -------------------------------------------------------------------- */
     305               6 :     CNCSError oErr;
     306                 : 
     307               6 :     poGDS->CleanupWindow();
     308                 : 
     309               6 :     iBand = nBand-1;
     310                 :     oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
     311                 :                                        nXOff, nYOff, 
     312                 :                                        nXOff + nXSize - 1, 
     313                 :                                        nYOff + nYSize - 1,
     314               6 :                                        nNewXSize, nNewYSize );
     315               6 :     if( oErr.GetErrorNumber() != NCS_SUCCESS )
     316                 :     {
     317               0 :         CPLFree( pabyWorkBuffer );
     318               0 :         char* pszErrorMessage = oErr.GetErrorMessage();
     319                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     320               0 :                   "%s", pszErrorMessage );
     321               0 :         NCSFree(pszErrorMessage);
     322                 :         
     323               0 :         return CE_Failure;
     324                 :     }
     325                 : 
     326                 : /* -------------------------------------------------------------------- */
     327                 : /*      Read back one scanline at a time, till request is satisfied.    */
     328                 : /*      Supersampling is not supported by the ECW API, so we will do    */
     329                 : /*      it ourselves.                                                   */
     330                 : /* -------------------------------------------------------------------- */
     331               6 :     double  dfSrcYInc = (double)nNewYSize / nBufYSize;
     332               6 :     double  dfSrcXInc = (double)nNewXSize / nBufXSize;
     333                 :     int         iSrcLine, iDstLine;
     334                 : 
     335            1518 :     for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
     336                 :     {
     337                 :         NCSEcwReadStatus eRStatus;
     338            1512 :         int         iDstLineOff = iDstLine * nLineSpace;
     339                 :         unsigned char *pabySrcBuf;
     340                 : 
     341            1512 :         if( bDirect )
     342            1472 :             pabySrcBuf = ((GByte *)pData) + iDstLineOff;
     343                 :         else
     344              40 :             pabySrcBuf = pabyWorkBuffer;
     345                 : 
     346            3024 :   if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
     347                 :   {
     348                 :             eRStatus = poGDS->poFileView->ReadLineBIL( 
     349            1512 :                 poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
     350                 : 
     351            1512 :       if( eRStatus != NCSECW_READ_OK )
     352                 :       {
     353               0 :           CPLFree( pabyWorkBuffer );
     354               0 :                 CPLDebug( "ECW", "ReadLineBIL status=%d", (int) eRStatus );
     355                 :           CPLError( CE_Failure, CPLE_AppDefined,
     356               0 :         "NCScbmReadViewLineBIL failed." );
     357               0 :     return CE_Failure;
     358                 :       }
     359                 : 
     360            1512 :             if( !bDirect )
     361                 :             {
     362              40 :                 if ( nNewXSize == nBufXSize )
     363                 :                 {
     364                 :                     GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType, 
     365                 :                                    nRawPixelSize, 
     366                 :                                    ((GByte *)pData) + iDstLine * nLineSpace, 
     367              40 :                                    eBufType, nPixelSpace, nBufXSize );
     368                 :                 }
     369                 :     else
     370                 :     {
     371                 :               int iPixel;
     372                 : 
     373               0 :                     for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
     374                 :                     {
     375                 :                         GDALCopyWords( pabyWorkBuffer 
     376                 :                                        + nRawPixelSize*((int)(iPixel*dfSrcXInc)),
     377                 :                                        poGDS->eRasterDataType, nRawPixelSize,
     378                 :                                        (GByte *)pData + iDstLineOff
     379                 :                + iPixel * nPixelSpace,
     380               0 :                                        eBufType, nPixelSpace, 1 );
     381                 :                     }
     382                 :     }
     383                 :             }
     384                 : 
     385            1512 :             iSrcLine++;
     386                 :   }
     387                 :   else
     388                 :   {
     389                 :       // Just copy the previous line in this case
     390                 :             GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
     391                 :                             eBufType, nPixelSpace,
     392                 :                             (GByte *)pData + iDstLineOff,
     393               0 :                             eBufType, nPixelSpace, nBufXSize );
     394                 :   }
     395                 :     }
     396                 : 
     397               6 :     CPLFree( pabyWorkBuffer );
     398                 : 
     399               6 :     return CE_None;
     400                 : }
     401                 : 
     402                 : /************************************************************************/
     403                 : /*                             IReadBlock()                             */
     404                 : /************************************************************************/
     405                 : 
     406              62 : CPLErr ECWRasterBand::IReadBlock( int, int nBlockYOff, void * pImage )
     407                 : 
     408                 : {
     409              62 :     CPLErr eErr = CE_None;
     410              62 :     int nXOff = 0, nYOff = nBlockYOff, nXSize = nBlockXSize, nYSize = 1;
     411              62 :     int nResFactor = 1 << (iOverview+1);
     412                 :     int nDSXOff, nDSYOff, nDSXSize, nDSYSize;
     413                 : 
     414              62 :     nDSXOff = nXOff * nResFactor;
     415              62 :     nDSYOff = nYOff * nResFactor;
     416              62 :     nDSXSize = nXSize * nResFactor;
     417              62 :     nDSYSize = nYSize * nResFactor;
     418                 : 
     419                 : #ifdef NOISY_DEBUG
     420                 :     CPLDebug( "ECW", 
     421                 :               "ECWRasterBand::IReadBlock(0,%d) from overview %d, size %dx%d",
     422                 :               nBlockYOff,
     423                 :               iOverview, nRasterXSize, nRasterYSize );
     424                 : #endif
     425                 : 
     426              62 :     if( poGDS->TryWinRasterIO( GF_Read, nDSXOff, nDSYOff, nDSXSize, nDSYSize,
     427                 :                                (GByte *) pImage, nBlockXSize, 1, 
     428                 :                                eDataType, 1, &nBand, 0, 0, 0 ) )
     429               0 :         return CE_None;
     430                 : 
     431                 :     eErr = AdviseRead( 0, nYOff, 
     432                 :                        nRasterXSize, nRasterYSize - nYOff,
     433                 :                        nRasterXSize, nRasterYSize - nBlockYOff,
     434              62 :                        eDataType, NULL );
     435              62 :     if( eErr != CE_None )
     436               0 :         return eErr;
     437                 : 
     438              62 :     if( poGDS->TryWinRasterIO( GF_Read, 
     439                 :                                nDSXOff, nDSYOff, nDSXSize, nDSYSize,
     440                 :                                (GByte *) pImage, nBlockXSize, 1, 
     441                 :                                eDataType, 1, &nBand, 0, 0, 0 ) )
     442              62 :         return CE_None;
     443                 : 
     444                 :     CPLError( CE_Failure, CPLE_AppDefined, 
     445                 :               "TryWinRasterIO() failed for blocked scanline %d of band %d.",
     446               0 :               nBlockYOff, nBand );
     447                 : 
     448               0 :     return CE_Failure;
     449                 : }
     450                 : 
     451                 : /************************************************************************/
     452                 : /* ==================================================================== */
     453                 : /*                            ECWDataset                               */
     454                 : /* ==================================================================== */
     455                 : /************************************************************************/
     456                 : 
     457                 : 
     458                 : /************************************************************************/
     459                 : /*                            ECWDataset()                              */
     460                 : /************************************************************************/
     461                 : 
     462             118 : ECWDataset::ECWDataset(int bIsJPEG2000)
     463                 : 
     464                 : {
     465             118 :     this->bIsJPEG2000 = bIsJPEG2000;
     466             118 :     bUsingCustomStream = FALSE;
     467             118 :     pszProjection = NULL;
     468             118 :     poFileView = NULL;
     469             118 :     bWinActive = FALSE;
     470             118 :     panWinBandList = NULL;
     471             118 :     eRasterDataType = GDT_Byte;
     472             118 :     nGCPCount = 0;
     473             118 :     pasGCPList = NULL;
     474             118 :     papszGMLMetadata = NULL;
     475                 :     
     476             118 :     bGeoTransformValid = FALSE;
     477             118 :     adfGeoTransform[0] = 0.0;
     478             118 :     adfGeoTransform[1] = 1.0;
     479             118 :     adfGeoTransform[2] = 0.0;
     480             118 :     adfGeoTransform[3] = 0.0;
     481             118 :     adfGeoTransform[4] = 0.0;
     482             118 :     adfGeoTransform[5] = 1.0;
     483                 : 
     484             118 :     bHdrDirty = FALSE;
     485             118 :     bGeoTransformChanged = FALSE;
     486             118 :     bProjectionChanged = FALSE;
     487             118 :     bProjCodeChanged = FALSE;
     488             118 :     bDatumCodeChanged = FALSE;
     489             118 :     bUnitsCodeChanged = FALSE;
     490                 :     
     491             118 :     poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
     492             118 : }
     493                 : 
     494                 : /************************************************************************/
     495                 : /*                           ~ECWDataset()                              */
     496                 : /************************************************************************/
     497                 : 
     498             118 : ECWDataset::~ECWDataset()
     499                 : 
     500                 : {
     501             118 :     FlushCache();
     502             118 :     CleanupWindow();
     503                 : 
     504                 : /* -------------------------------------------------------------------- */
     505                 : /*      Release / dereference iostream.                                 */
     506                 : /* -------------------------------------------------------------------- */
     507                 :     // The underlying iostream of the CNCSJP2FileView (poFileView) object may 
     508                 :     // also be the underlying iostream of other CNCSJP2FileView (poFileView) 
     509                 :     // objects.  Consequently, when we delete the CNCSJP2FileView (poFileView) 
     510                 :     // object, we must decrement the nFileViewCount attribute of the underlying
     511                 :     // VSIIOStream object, and only delete the VSIIOStream object when 
     512                 :     // nFileViewCount is equal to zero.
     513                 : 
     514             118 :     CPLMutexHolder oHolder( &hECWDatasetMutex );
     515                 : 
     516             118 :     if( poFileView != NULL )
     517                 :     {
     518             118 :         VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
     519                 : 
     520             118 :         poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
     521             118 :         delete poFileView;
     522                 : 
     523             118 :         if( bUsingCustomStream )
     524                 :         {
     525              30 :             if( --poUnderlyingIOStream->nFileViewCount == 0 )
     526              30 :                 delete poUnderlyingIOStream;
     527                 :         }
     528                 :     }
     529                 : 
     530                 :     /* WriteHeader() must be called after closing the file handle to work */
     531                 :     /* on Windows */
     532             118 :     if( bHdrDirty )
     533               6 :         WriteHeader();
     534                 : 
     535             118 :     CPLFree( pszProjection );
     536             118 :     CSLDestroy( papszGMLMetadata );
     537                 : 
     538             118 :     if( nGCPCount > 0 )
     539                 :     {
     540               8 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     541               8 :         CPLFree( pasGCPList );
     542             118 :     }
     543             118 : }
     544                 : 
     545                 : /************************************************************************/
     546                 : /*                             AdviseRead()                             */
     547                 : /************************************************************************/
     548                 : 
     549              12 : CPLErr ECWDataset::SetGeoTransform( double * padfGeoTransform )
     550                 : {
     551              12 :     if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
     552              10 :         return GDALPamDataset::SetGeoTransform(padfGeoTransform);
     553                 : 
     554               4 :     if ( !bGeoTransformValid ||
     555               2 :         adfGeoTransform[0] != padfGeoTransform[0] ||
     556               0 :         adfGeoTransform[1] != padfGeoTransform[1] ||
     557               0 :         adfGeoTransform[2] != padfGeoTransform[2] ||
     558               0 :         adfGeoTransform[3] != padfGeoTransform[3] ||
     559               0 :         adfGeoTransform[4] != padfGeoTransform[4] ||
     560               0 :         adfGeoTransform[5] != padfGeoTransform[5] )
     561                 :     {
     562               2 :         memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
     563               2 :         bGeoTransformValid = TRUE;
     564               2 :         bHdrDirty = TRUE;
     565               2 :         bGeoTransformChanged = TRUE;
     566                 :     }
     567                 : 
     568               2 :     return CE_None;
     569                 : }
     570                 : 
     571                 : /************************************************************************/
     572                 : /*                            SetProjection()                           */
     573                 : /************************************************************************/
     574                 : 
     575              12 : CPLErr ECWDataset::SetProjection( const char* pszProjectionIn )
     576                 : {
     577              12 :     if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
     578              10 :         return GDALPamDataset::SetProjection(pszProjectionIn);
     579                 : 
     580               2 :     if ( !( (pszProjection == NULL && pszProjectionIn == NULL) ||
     581                 :             (pszProjection != NULL && pszProjectionIn != NULL &&
     582                 :              strcmp(pszProjection, pszProjectionIn) == 0) ) )
     583                 :     {
     584               2 :         CPLFree(pszProjection);
     585               2 :         pszProjection = pszProjectionIn ? CPLStrdup(pszProjectionIn) : NULL;
     586               2 :         bHdrDirty = TRUE;
     587               2 :         bProjectionChanged = TRUE;
     588                 :     }
     589                 : 
     590               2 :     return CE_None;
     591                 : }
     592                 : 
     593                 : /************************************************************************/
     594                 : /*                            SetMetadataItem()                         */
     595                 : /************************************************************************/
     596                 : 
     597               6 : CPLErr ECWDataset::SetMetadataItem( const char * pszName,
     598                 :                                     const char * pszValue,
     599                 :                                     const char * pszDomain )
     600                 : {
     601               6 :     if ( !bIsJPEG2000 && eAccess == GA_Update &&
     602                 :          (pszDomain == NULL || EQUAL(pszDomain, "") ||
     603                 :           (pszDomain != NULL && EQUAL(pszDomain, "ECW"))) &&
     604                 :          pszName != NULL &&
     605                 :          (strcmp(pszName, "PROJ") == 0 || strcmp( pszName, "DATUM") == 0 ||
     606                 :           strcmp( pszName, "UNITS") == 0 ) )
     607                 :     {
     608               6 :         CPLString osNewVal = pszValue ? pszValue : "";
     609               6 :         if (osNewVal.size() > 31)
     610               0 :             osNewVal.resize(31);
     611               6 :         if (strcmp(pszName, "PROJ") == 0)
     612                 :         {
     613               2 :             bProjCodeChanged = (osNewVal != m_osProjCode);
     614               2 :             m_osProjCode = osNewVal;
     615               2 :             bHdrDirty |= bProjCodeChanged;
     616                 :         }
     617               4 :         else if (strcmp( pszName, "DATUM") == 0)
     618                 :         {
     619               2 :             bDatumCodeChanged |= (osNewVal != m_osDatumCode);
     620               2 :             m_osDatumCode = osNewVal;
     621               2 :             bHdrDirty |= bDatumCodeChanged;
     622                 :         }
     623                 :         else 
     624                 :         {
     625               2 :             bUnitsCodeChanged |= (osNewVal != m_osUnitsCode);
     626               2 :             m_osUnitsCode = osNewVal;
     627               2 :             bHdrDirty |= bUnitsCodeChanged;
     628                 :         }
     629               6 :         return CE_None;
     630                 :     }
     631                 :     else
     632               0 :         return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
     633                 : }
     634                 : 
     635                 : /************************************************************************/
     636                 : /*                              SetMetadata()                           */
     637                 : /************************************************************************/
     638                 : 
     639              30 : CPLErr ECWDataset::SetMetadata( char ** papszMetadata,
     640                 :                                 const char * pszDomain )
     641                 : {
     642              30 :     if ( (pszDomain == NULL || EQUAL(pszDomain, "") || EQUAL(pszDomain, "ECW")) &&
     643                 :           (CSLFetchNameValue(papszMetadata, "PROJ") != NULL ||
     644                 :            CSLFetchNameValue(papszMetadata, "DATUM") != NULL ||
     645                 :            CSLFetchNameValue(papszMetadata, "UNITS") != NULL) )
     646                 :     {
     647               0 :         CPLStringList osNewMetadata;
     648               0 :         char** papszIter = papszMetadata;
     649               0 :         while(*papszIter)
     650                 :         {
     651               0 :             if (strncmp(*papszIter, "PROJ=", 5) == 0 ||
     652                 :                 strncmp(*papszIter, "DATUM=", 6) == 0 ||
     653                 :                 strncmp(*papszIter, "UNITS=", 6) == 0)
     654                 :             {
     655               0 :                 char* pszKey = NULL;
     656               0 :                 const char* pszValue = CPLParseNameValue(*papszIter, &pszKey );
     657               0 :                 SetMetadataItem(pszKey, pszValue, pszDomain);
     658               0 :                 CPLFree(pszKey);
     659                 :             }
     660                 :             else
     661               0 :                 osNewMetadata.AddString(*papszIter);
     662               0 :             papszIter ++;
     663                 :         }
     664               0 :         if (osNewMetadata.size() != 0)
     665               0 :             return GDALPamDataset::SetMetadata(osNewMetadata.List(), pszDomain);
     666                 :         else
     667               0 :             return CE_None;
     668                 :     }
     669                 :     else
     670              30 :         return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
     671                 : }
     672                 : 
     673                 : /************************************************************************/
     674                 : /*                             WriteHeader()                            */
     675                 : /************************************************************************/
     676                 : 
     677               6 : void ECWDataset::WriteHeader()
     678                 : {
     679               6 :     if (!bHdrDirty)
     680               0 :         return;
     681                 : 
     682               6 :     CPLAssert(eAccess == GA_Update);
     683               6 :     CPLAssert(!bIsJPEG2000);
     684                 : 
     685               6 :     bHdrDirty = FALSE;
     686                 : 
     687               6 :     NCSEcwEditInfo *psEditInfo = NULL;
     688                 :     NCSError eErr;
     689                 : 
     690                 :     /* Load original header info */
     691               6 :     eErr = NCSEcwEditReadInfo((char*) GetDescription(), &psEditInfo);
     692               6 :     if (eErr != NCS_SUCCESS)
     693                 :     {
     694               0 :         CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditReadInfo() failed");
     695               0 :         return;
     696                 :     }
     697                 : 
     698                 :     /* To avoid potential cross-heap issues, we keep the original */
     699                 :     /* strings, and restore them before freeing the structure */
     700               6 :     char* pszOriginalCode = psEditInfo->szDatum;
     701               6 :     char* pszOriginalProj = psEditInfo->szProjection;
     702                 : 
     703                 :     /* Alter the structure with user modified information */
     704                 :     char szProjCode[32], szDatumCode[32], szUnits[32];
     705               6 :     if (bProjectionChanged)
     706                 :     {
     707               2 :         if (ECWTranslateFromWKT( pszProjection, szProjCode, sizeof(szProjCode),
     708                 :                                  szDatumCode, sizeof(szDatumCode), szUnits ) )
     709                 :         {
     710               2 :             psEditInfo->szDatum = szDatumCode;
     711               2 :             psEditInfo->szProjection = szProjCode;
     712               2 :             psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
     713               2 :             CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
     714               2 :             CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
     715                 :             CPLDebug("ECW", "Rewrite UNITS : %s",
     716               2 :                      ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
     717                 :         }
     718                 :     }
     719                 : 
     720               6 :     if (bDatumCodeChanged)
     721                 :     {
     722               2 :         psEditInfo->szDatum = (char*) ((m_osDatumCode.size()) ? m_osDatumCode.c_str() : "RAW");
     723               2 :         CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
     724                 :     }
     725               6 :     if (bProjCodeChanged)
     726                 :     {
     727               2 :         psEditInfo->szProjection = (char*) ((m_osProjCode.size()) ? m_osProjCode.c_str() : "RAW");
     728               2 :         CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
     729                 :     }
     730               6 :     if (bUnitsCodeChanged)
     731                 :     {
     732               2 :         psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(m_osUnitsCode.c_str());
     733                 :         CPLDebug("ECW", "Rewrite UNITS : %s",
     734               2 :                  ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
     735                 :     }
     736                 : 
     737               6 :     if (bGeoTransformChanged)
     738                 :     {
     739               2 :         psEditInfo->fOriginX = adfGeoTransform[0];
     740               2 :         psEditInfo->fCellIncrementX = adfGeoTransform[1];
     741               2 :         psEditInfo->fOriginY = adfGeoTransform[3];
     742               2 :         psEditInfo->fCellIncrementY = adfGeoTransform[5];
     743               2 :         CPLDebug("ECW", "Rewrite Geotransform");
     744                 :     }
     745                 : 
     746                 :     /* Write modified header info */
     747               6 :     eErr = NCSEcwEditWriteInfo((char*) GetDescription(), psEditInfo, NULL, NULL, NULL);
     748               6 :     if (eErr != NCS_SUCCESS)
     749                 :     {
     750               0 :         CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditWriteInfo() failed");
     751                 :     }
     752                 : 
     753                 :     /* Restore original pointers before free'ing */
     754               6 :     psEditInfo->szDatum = pszOriginalCode;
     755               6 :     psEditInfo->szProjection = pszOriginalProj;
     756                 : 
     757               6 :     NCSEcwEditFreeInfo(psEditInfo);
     758                 : }
     759                 : 
     760                 : /************************************************************************/
     761                 : /*                             AdviseRead()                             */
     762                 : /************************************************************************/
     763                 : 
     764              64 : CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     765                 :                                int nBufXSize, int nBufYSize, 
     766                 :                                GDALDataType eDT, 
     767                 :                                int nBandCount, int *panBandList,
     768                 :                                char **papszOptions )
     769                 : 
     770                 : {
     771              64 :     int *panAdjustedBandList = NULL;
     772                 : 
     773                 :     CPLDebug( "ECW",
     774                 :               "ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
     775              64 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     776                 : 
     777              64 :     if( nBufXSize > nXSize || nBufYSize > nYSize )
     778                 :     {
     779                 :         CPLError( CE_Warning, CPLE_AppDefined, 
     780                 :                   "Supersampling not directly supported by ECW toolkit,\n"
     781               0 :                   "ignoring AdviseRead() request." );
     782               0 :         return CE_Warning; 
     783                 :     }
     784                 : 
     785                 : /* -------------------------------------------------------------------- */
     786                 : /*      Adjust band numbers to be zero based.                           */
     787                 : /* -------------------------------------------------------------------- */
     788                 :     panAdjustedBandList = (int *) 
     789              64 :         CPLMalloc(sizeof(int) * nBandCount );
     790             132 :     for( int ii= 0; ii < nBandCount; ii++ )
     791              68 :         panAdjustedBandList[ii] = panBandList[ii] - 1;
     792                 : 
     793                 : /* -------------------------------------------------------------------- */
     794                 : /*      Cleanup old window cache information.                           */
     795                 : /* -------------------------------------------------------------------- */
     796              64 :     CleanupWindow();
     797                 : 
     798                 : /* -------------------------------------------------------------------- */
     799                 : /*      Set the new requested window.                                   */
     800                 : /* -------------------------------------------------------------------- */
     801              64 :     CNCSError oErr;
     802                 :     
     803                 :     oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList, 
     804                 :                                 nXOff, nYOff, 
     805                 :                                 nXOff + nXSize-1, nYOff + nYSize-1,
     806              64 :                                 nBufXSize, nBufYSize );
     807                 : 
     808              64 :     CPLFree( panAdjustedBandList );
     809              64 :     if( oErr.GetErrorNumber() != NCS_SUCCESS )
     810                 :     {
     811               0 :         char* pszErrorMessage = oErr.GetErrorMessage();
     812                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     813               0 :                   "%s", pszErrorMessage );
     814               0 :         NCSFree(pszErrorMessage);
     815               0 :         bWinActive = FALSE;
     816               0 :         return CE_Failure;
     817                 :     }
     818                 : 
     819              64 :     bWinActive = TRUE;
     820                 : 
     821                 : /* -------------------------------------------------------------------- */
     822                 : /*      Record selected window.                                         */
     823                 : /* -------------------------------------------------------------------- */
     824              64 :     nWinXOff = nXOff;
     825              64 :     nWinYOff = nYOff;
     826              64 :     nWinXSize = nXSize;
     827              64 :     nWinYSize = nYSize;
     828              64 :     nWinBufXSize = nBufXSize;
     829              64 :     nWinBufYSize = nBufYSize;
     830                 : 
     831              64 :     panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
     832              64 :     memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
     833              64 :     nWinBandCount = nBandCount;
     834                 : 
     835              64 :     nWinBufLoaded = -1;
     836                 : 
     837                 : /* -------------------------------------------------------------------- */
     838                 : /*      Allocate current scanline buffer.                               */
     839                 : /* -------------------------------------------------------------------- */
     840              64 :     papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
     841             132 :     for( int iBand = 0; iBand < nWinBandCount; iBand++ )
     842              68 :         papCurLineBuf[iBand] = 
     843              68 :             CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
     844                 :         
     845              64 :     return CE_None;
     846                 : }
     847                 : 
     848                 : /************************************************************************/
     849                 : /*                           TryWinRasterIO()                           */
     850                 : /*                                                                      */
     851                 : /*      Try to satisfy the given request based on the currently         */
     852                 : /*      defined window.  Return TRUE on success or FALSE on             */
     853                 : /*      failure.  On failure, the caller should satisfy the request     */
     854                 : /*      another way (not report an error).                              */
     855                 : /************************************************************************/
     856                 : 
     857           26380 : int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag, 
     858                 :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     859                 :                                 GByte *pabyData, int nBufXSize, int nBufYSize, 
     860                 :                                 GDALDataType eDT,
     861                 :                                 int nBandCount, int *panBandList, 
     862                 :                                 int nPixelSpace, int nLineSpace, 
     863                 :                                 int nBandSpace )
     864                 : 
     865                 : {
     866                 :     int iBand, i;
     867                 : 
     868                 : /* -------------------------------------------------------------------- */
     869                 : /*      Provide default buffer organization.                            */
     870                 : /* -------------------------------------------------------------------- */
     871           26380 :     if( nPixelSpace == 0 )
     872             124 :         nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
     873           26380 :     if( nLineSpace == 0 )
     874             124 :         nLineSpace = nPixelSpace * nBufXSize;
     875           26380 :     if( nBandSpace == 0 )
     876           25574 :         nBandSpace = nLineSpace * nBufYSize;
     877                 : 
     878                 : /* -------------------------------------------------------------------- */
     879                 : /*      Do some simple tests to see if the current window can           */
     880                 : /*      satisfy our requirement.                                        */
     881                 : /* -------------------------------------------------------------------- */
     882                 : #ifdef NOISY_DEBUG
     883                 :     CPLDebug( "ECW", "TryWinRasterIO(%d,%d,%d,%d,%d,%d)", 
     884                 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     885                 : #endif
     886                 : 
     887           26380 :     if( !bWinActive )
     888             104 :         return FALSE;
     889                 :     
     890           26276 :     if( nXOff != nWinXOff || nXSize != nWinXSize )
     891               0 :         return FALSE;
     892                 : 
     893           26276 :     if( nBufXSize != nWinBufXSize )
     894               0 :         return FALSE;
     895                 : 
     896           54120 :     for( iBand = 0; iBand < nBandCount; iBand++ )
     897                 :     {
     898           30308 :         for( i = 0; i < nWinBandCount; i++ )
     899                 :         {
     900           30276 :             if( panWinBandList[i] == panBandList[iBand] )
     901           27844 :                 break;
     902                 :         }
     903                 : 
     904           27876 :         if( i == nWinBandCount )
     905              32 :             return FALSE;
     906                 :     }
     907                 : 
     908           26244 :     if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
     909               0 :         return FALSE;
     910                 : 
     911                 : /* -------------------------------------------------------------------- */
     912                 : /*      Now we try more subtle tests.                                   */
     913                 : /* -------------------------------------------------------------------- */
     914                 :     {
     915                 :         static int nDebugCount = 0;
     916                 : 
     917           26244 :         if( nDebugCount < 30 )
     918                 :             CPLDebug( "ECWDataset", 
     919                 :                       "TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.", 
     920              60 :                       nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     921                 : 
     922           26244 :         if( nDebugCount == 29 )
     923               2 :             CPLDebug( "ECWDataset", "No more TryWinRasterIO messages will be reported" );
     924                 :         
     925           26244 :         nDebugCount++;
     926                 :     }
     927                 : 
     928                 : /* -------------------------------------------------------------------- */
     929                 : /*      Actually load data one buffer line at a time.                   */
     930                 : /* -------------------------------------------------------------------- */
     931                 :     int iBufLine;
     932                 : 
     933           52488 :     for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
     934                 :     {
     935           26244 :         double fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
     936                 :         int iWinLine = 
     937           26244 :             (int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
     938                 :         
     939           26244 :         if( iWinLine == nWinBufLoaded + 1 )
     940           26244 :             LoadNextLine();
     941                 : 
     942           26244 :         if( iWinLine != nWinBufLoaded )
     943               0 :             return FALSE;
     944                 : 
     945                 : /* -------------------------------------------------------------------- */
     946                 : /*      Copy out all our target bands.                                  */
     947                 : /* -------------------------------------------------------------------- */
     948                 :         int iWinBand;
     949           54088 :         for( iBand = 0; iBand < nBandCount; iBand++ )
     950                 :         {
     951           30244 :             for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
     952                 :             {
     953           30244 :                 if( panWinBandList[iWinBand] == panBandList[iBand] )
     954           27844 :                     break;
     955                 :             }
     956                 : 
     957                 :             GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
     958                 :                            GDALGetDataTypeSize( eRasterDataType ) / 8, 
     959                 :                            pabyData + nBandSpace * iBand 
     960                 :                            + iBufLine * nLineSpace, eDT, nPixelSpace,
     961           27844 :                            nBufXSize );
     962                 :         }
     963                 :     }
     964                 : 
     965           26244 :     return TRUE;
     966                 : }
     967                 : 
     968                 : /************************************************************************/
     969                 : /*                            LoadNextLine()                            */
     970                 : /************************************************************************/
     971                 : 
     972           26244 : CPLErr ECWDataset::LoadNextLine()
     973                 : 
     974                 : {
     975           26244 :     if( !bWinActive )
     976               0 :         return CE_Failure;
     977                 : 
     978           26244 :     if( nWinBufLoaded == nWinBufYSize-1 )
     979                 :     {
     980               0 :         CleanupWindow();
     981               0 :         return CE_Failure;
     982                 :     }
     983                 : 
     984                 :     NCSEcwReadStatus  eRStatus;
     985                 :     eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, 
     986                 :                                         (UINT16) nWinBandCount,
     987           26244 :                                         papCurLineBuf );
     988           26244 :     if( eRStatus != NCSECW_READ_OK )
     989               0 :         return CE_Failure;
     990                 : 
     991           26244 :     nWinBufLoaded++;
     992                 : 
     993           26244 :     return CE_None;
     994                 : }
     995                 : 
     996                 : /************************************************************************/
     997                 : /*                           CleanupWindow()                            */
     998                 : /************************************************************************/
     999                 : 
    1000             192 : void ECWDataset::CleanupWindow()
    1001                 : 
    1002                 : {
    1003             192 :     if( !bWinActive )
    1004             128 :         return;
    1005                 : 
    1006              64 :     bWinActive = FALSE;
    1007              64 :     CPLFree( panWinBandList );
    1008              64 :     panWinBandList = NULL;
    1009                 : 
    1010             132 :     for( int iBand = 0; iBand < nWinBandCount; iBand++ )
    1011              68 :         CPLFree( papCurLineBuf[iBand] );
    1012              64 :     CPLFree( papCurLineBuf );
    1013              64 :     papCurLineBuf = NULL;
    1014                 : }
    1015                 : 
    1016                 : /************************************************************************/
    1017                 : /*                             IRasterIO()                              */
    1018                 : /************************************************************************/
    1019                 : 
    1020             804 : CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
    1021                 :                               int nXOff, int nYOff, int nXSize, int nYSize,
    1022                 :                               void * pData, int nBufXSize, int nBufYSize,
    1023                 :                               GDALDataType eBufType, 
    1024                 :                               int nBandCount, int *panBandMap,
    1025                 :                               int nPixelSpace, int nLineSpace, int nBandSpace)
    1026                 :     
    1027                 : {
    1028                 : /* -------------------------------------------------------------------- */
    1029                 : /*      Try to do it based on existing "advised" access.                */
    1030                 : /* -------------------------------------------------------------------- */
    1031             804 :     if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
    1032                 :                         (GByte *) pData, nBufXSize, nBufYSize, 
    1033                 :                         eBufType, nBandCount, panBandMap,
    1034                 :                         nPixelSpace, nLineSpace, nBandSpace ) )
    1035             798 :         return CE_None;
    1036                 : 
    1037                 : /* -------------------------------------------------------------------- */
    1038                 : /*      If we are requesting a single line at 1:1, we do a multi-band   */
    1039                 : /*      AdviseRead() and then TryWinRasterIO() again.                   */
    1040                 : /* -------------------------------------------------------------------- */
    1041               6 :     if( nYSize == 1 && nBufYSize == 1 && nBandCount > 1 )
    1042                 :     {
    1043                 :         CPLErr eErr;
    1044                 : 
    1045                 :         eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
    1046                 :                            nBufXSize, GetRasterYSize() - nYOff, eBufType, 
    1047               2 :                            nBandCount, panBandMap, NULL );
    1048               2 :         if( eErr == CE_None 
    1049                 :             && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
    1050                 :                                (GByte *) pData, nBufXSize, nBufYSize, 
    1051                 :                                eBufType, nBandCount, panBandMap,
    1052                 :                                nPixelSpace, nLineSpace, nBandSpace ) )
    1053               2 :             return CE_None;
    1054                 :     }
    1055                 : 
    1056                 : /* -------------------------------------------------------------------- */
    1057                 : /*      If we are supersampling we need to fall into the general        */
    1058                 : /*      purpose logic.  We also use the general logic if we are in      */
    1059                 : /*      some cases unlikely to benefit from interleaved access.         */
    1060                 : /*                                                                      */
    1061                 : /*      The one case we would like to handle better here is the         */
    1062                 : /*      nBufYSize == 1 case (requesting a scanline at a time).  We      */
    1063                 : /*      should eventually have some logic similiar to the band by       */
    1064                 : /*      band case where we post a big window for the view, and allow    */
    1065                 : /*      sequential reads.                                               */
    1066                 : /* -------------------------------------------------------------------- */
    1067               4 :     if( nXSize < nBufXSize || nYSize < nBufYSize || nYSize == 1 
    1068                 :         || nBandCount > 100 || nBandCount == 1 || nBufYSize == 1 
    1069                 :         || nBandCount > GetRasterCount() )
    1070                 :     {
    1071                 :         return 
    1072                 :             GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1073                 :                                     pData, nBufXSize, nBufYSize,
    1074                 :                                     eBufType, 
    1075                 :                                     nBandCount, panBandMap,
    1076               0 :                                     nPixelSpace, nLineSpace, nBandSpace);
    1077                 :     }
    1078                 : 
    1079                 :     CPLDebug( "ECWDataset", 
    1080                 :               "RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.", 
    1081               4 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
    1082                 : 
    1083                 : /* -------------------------------------------------------------------- */
    1084                 : /*      Setup view.                                                     */
    1085                 : /* -------------------------------------------------------------------- */
    1086                 :     UINT32 anBandIndices[100];
    1087                 :     int    i;
    1088                 :     NCSError     eNCSErr;
    1089               4 :     CNCSError    oErr;
    1090                 :     
    1091              16 :     for( i = 0; i < nBandCount; i++ )
    1092              12 :         anBandIndices[i] = panBandMap[i] - 1;
    1093                 : 
    1094               4 :     CleanupWindow();
    1095                 : 
    1096                 :     oErr = poFileView->SetView( nBandCount, anBandIndices,
    1097                 :                                 nXOff, nYOff, 
    1098                 :                                 nXOff + nXSize - 1, 
    1099                 :                                 nYOff + nYSize - 1,
    1100               4 :                                 nBufXSize, nBufYSize );
    1101               4 :     eNCSErr = oErr.GetErrorNumber();
    1102                 :     
    1103               4 :     if( eNCSErr != NCS_SUCCESS )
    1104                 :     {
    1105                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1106               0 :                   "%s", NCSGetErrorText(eNCSErr) );
    1107                 :         
    1108               0 :         return CE_Failure;
    1109                 :     }
    1110                 : 
    1111                 : /* -------------------------------------------------------------------- */
    1112                 : /*      Setup working scanline, and the pointers into it.               */
    1113                 : /* -------------------------------------------------------------------- */
    1114               4 :     int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
    1115                 :     GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
    1116               4 :                                                  nBandCount);
    1117               4 :     GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
    1118                 : 
    1119              16 :     for( i = 0; i < nBandCount; i++ )
    1120              12 :         papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
    1121                 : 
    1122                 : /* -------------------------------------------------------------------- */
    1123                 : /*      Read back all the data for the requested view.                  */
    1124                 : /* -------------------------------------------------------------------- */
    1125             884 :     for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
    1126                 :     {
    1127                 :         NCSEcwReadStatus  eRStatus;
    1128                 : 
    1129                 :         eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, 
    1130                 :                                             (UINT16) nBandCount,
    1131             880 :                                             (void **) papabyBIL );
    1132             880 :         if( eRStatus != NCSECW_READ_OK )
    1133                 :         {
    1134               0 :             CPLFree( papabyBIL );
    1135               0 :             CPLFree( pabyBILScanline );
    1136                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1137               0 :                       "NCScbmReadViewLineBIL failed." );
    1138               0 :             return CE_Failure;
    1139                 :         }
    1140                 : 
    1141            3520 :         for( i = 0; i < nBandCount; i++ )
    1142                 :         {
    1143                 :             GDALCopyWords( 
    1144                 :                 pabyBILScanline + i * nDataTypeSize * nBufXSize,
    1145                 :                 eRasterDataType, nDataTypeSize, 
    1146                 :                 ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i, 
    1147                 :                 eBufType, nPixelSpace, 
    1148            2640 :                 nBufXSize );
    1149                 :         }
    1150                 :     }
    1151                 : 
    1152               4 :     CPLFree( pabyBILScanline );
    1153               4 :     CPLFree( papabyBIL );
    1154                 : 
    1155               4 :     return CE_None;
    1156                 : }
    1157                 : 
    1158                 : /************************************************************************/
    1159                 : /*                        IdentifyJPEG2000()                            */
    1160                 : /*                                                                      */
    1161                 : /*          Open method that only supports JPEG2000 files.              */
    1162                 : /************************************************************************/
    1163                 : 
    1164           22680 : int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
    1165                 : 
    1166                 : {
    1167           22680 :     if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
    1168               0 :         return TRUE;
    1169                 : 
    1170           22680 :     else if( poOpenInfo->nHeaderBytes >= 16 
    1171                 :         && (memcmp( poOpenInfo->pabyHeader, jpc_header, 
    1172                 :                     sizeof(jpc_header) ) == 0
    1173                 :             || memcmp( poOpenInfo->pabyHeader, jp2_header, 
    1174                 :                     sizeof(jp2_header) ) == 0) )
    1175              86 :         return TRUE;
    1176                 :     
    1177                 :     else
    1178           22594 :         return FALSE;
    1179                 : }
    1180                 : 
    1181                 : /************************************************************************/
    1182                 : /*                            OpenJPEG2000()                            */
    1183                 : /*                                                                      */
    1184                 : /*          Open method that only supports JPEG2000 files.              */
    1185                 : /************************************************************************/
    1186                 : 
    1187            3802 : GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
    1188                 : 
    1189                 : {
    1190            3802 :     if (!IdentifyJPEG2000(poOpenInfo))
    1191            3716 :         return NULL;
    1192                 : 
    1193              86 :     return Open( poOpenInfo, TRUE );
    1194                 : }
    1195                 :     
    1196                 : /************************************************************************/
    1197                 : /*                           IdentifyECW()                              */
    1198                 : /*                                                                      */
    1199                 : /*      Identify method that only supports ECW files.                   */
    1200                 : /************************************************************************/
    1201                 : 
    1202           23890 : int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
    1203                 : 
    1204                 : {
    1205                 : /* -------------------------------------------------------------------- */
    1206                 : /*      This has to either be a file on disk ending in .ecw or a        */
    1207                 : /*      ecwp: protocol url.                                             */
    1208                 : /* -------------------------------------------------------------------- */
    1209           23890 :     if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
    1210                 :          || poOpenInfo->nHeaderBytes == 0)
    1211                 :         && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5)
    1212                 :         && !EQUALN(poOpenInfo->pszFilename,"ecwps:",5) )
    1213           23856 :         return FALSE;
    1214                 : 
    1215              34 :     return TRUE;
    1216                 : }
    1217                 : 
    1218                 : /************************************************************************/
    1219                 : /*                              OpenECW()                               */
    1220                 : /*                                                                      */
    1221                 : /*      Open method that only supports ECW files.                       */
    1222                 : /************************************************************************/
    1223                 : 
    1224            4980 : GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
    1225                 : 
    1226                 : {
    1227            4980 :     if (!IdentifyECW(poOpenInfo))
    1228            4946 :         return NULL;
    1229                 : 
    1230              34 :     return Open( poOpenInfo, FALSE );
    1231                 : }
    1232                 : 
    1233                 : /************************************************************************/
    1234                 : /*                            OpenFileView()                            */
    1235                 : /************************************************************************/
    1236                 : 
    1237             120 : CNCSJP2FileView *ECWDataset::OpenFileView( const char *pszDatasetName,
    1238                 :                                            bool bProgressive,
    1239                 :                                            int &bUsingCustomStream )
    1240                 : 
    1241                 : {
    1242                 : /* -------------------------------------------------------------------- */
    1243                 : /*      First we try to open it as a normal CNCSFile, letting the       */
    1244                 : /*      ECW SDK manage the IO itself.   This will only work for real    */
    1245                 : /*      files, and ecwp: or ecwps: sources.                             */
    1246                 : /* -------------------------------------------------------------------- */
    1247             120 :     CNCSJP2FileView *poFileView = NULL;
    1248                 :     NCSError         eErr;
    1249             120 :     CNCSError        oErr;
    1250                 : 
    1251             120 :     bUsingCustomStream = FALSE;
    1252             120 :     poFileView = new CNCSFile();
    1253             240 :     oErr = poFileView->Open( (char *) pszDatasetName, bProgressive );
    1254             120 :     eErr = oErr.GetErrorNumber();
    1255                 : 
    1256                 : /* -------------------------------------------------------------------- */
    1257                 : /*      If that did not work, trying opening as a virtual file.         */
    1258                 : /* -------------------------------------------------------------------- */
    1259             120 :     if( eErr != NCS_SUCCESS )
    1260                 :     {
    1261                 :         CPLDebug( "ECW", 
    1262                 :                   "NCScbmOpenFileView(%s): eErr=%d, will try VSIL stream.", 
    1263              32 :                   pszDatasetName, (int) eErr );
    1264                 : 
    1265              32 :         delete poFileView;
    1266                 : 
    1267              32 :         VSILFILE *fpVSIL = VSIFOpenL( pszDatasetName, "rb" );
    1268              32 :         if( fpVSIL == NULL )
    1269                 :         {
    1270                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1271               0 :                       "Failed to open %s.", pszDatasetName );
    1272               0 :             return NULL;
    1273                 :         }
    1274                 : 
    1275              32 :         if( hECWDatasetMutex == NULL )
    1276                 :         {
    1277               0 :             hECWDatasetMutex = CPLCreateMutex();
    1278                 :         }
    1279              32 :         else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
    1280                 :         {
    1281               0 :             CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
    1282                 :         }
    1283                 :         else
    1284                 :         {
    1285              32 :             CPLDebug( "ECW", "Got mutex." );
    1286                 :         }
    1287              32 :         VSIIOStream *poIOStream = new VSIIOStream();
    1288              64 :         poIOStream->Access( fpVSIL, FALSE, pszDatasetName, 0, -1 );
    1289                 : 
    1290              32 :         poFileView = new CNCSJP2FileView();
    1291              64 :         oErr = poFileView->Open( poIOStream, bProgressive );
    1292                 : 
    1293                 :         // The CNCSJP2FileView (poFileView) object may not use the iostream 
    1294                 :         // (poIOStream) passed to the CNCSJP2FileView::Open() method if an 
    1295                 :         // iostream is already available to the ECW JPEG 2000 SDK for a given
    1296                 :         // file.  Consequently, if the iostream passed to 
    1297                 :         // CNCSJP2FileView::Open() does not become the underlying iostream 
    1298                 :         // of the CNCSJP2FileView object, then it should be deleted.
    1299                 :         //
    1300                 :         // In addition, the underlying iostream of the CNCSJP2FileView object
    1301                 :         // should not be deleted until all CNCSJP2FileView objects using the 
    1302                 :         // underlying iostream are deleted. Consequently, each time a 
    1303                 :         // CNCSJP2FileView object is created, the nFileViewCount attribute 
    1304                 :         // of the underlying VSIIOStream object must be incremented for use 
    1305                 :         // in the ECWDataset destructor.
    1306                 :       
    1307                 :         VSIIOStream * poUnderlyingIOStream = 
    1308              32 :             ((VSIIOStream *)(poFileView->GetStream()));
    1309                 : 
    1310              32 :         if ( poUnderlyingIOStream )
    1311              30 :             poUnderlyingIOStream->nFileViewCount++;
    1312                 : 
    1313              32 :         if ( poIOStream != poUnderlyingIOStream ) 
    1314                 :         {
    1315               2 :             delete poIOStream;
    1316                 :         }
    1317                 :         else
    1318                 :         {
    1319              30 :             bUsingCustomStream = TRUE;
    1320                 :         }
    1321                 : 
    1322              32 :         CPLReleaseMutex( hECWDatasetMutex );
    1323                 : 
    1324              32 :         if( oErr.GetErrorNumber() != NCS_SUCCESS )
    1325                 :         {
    1326               2 :             if (poFileView)
    1327               2 :                 delete poFileView;
    1328                 : 
    1329               2 :             char* pszErrorMessage = oErr.GetErrorMessage();
    1330                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1331               2 :                       "%s", pszErrorMessage );
    1332               2 :             NCSFree(pszErrorMessage);
    1333                 : 
    1334               2 :             return NULL;
    1335                 :         }
    1336                 :     }
    1337                 :     
    1338             118 :     return poFileView;
    1339                 : }
    1340                 : 
    1341                 : /************************************************************************/
    1342                 : /*                                Open()                                */
    1343                 : /************************************************************************/
    1344                 : 
    1345             120 : GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
    1346                 : 
    1347                 : {
    1348             120 :     CNCSJP2FileView *poFileView = NULL;
    1349                 :     int              i;
    1350             120 :     int              bUsingCustomStream = FALSE;
    1351             120 :     CPLString        osFilename = poOpenInfo->pszFilename;
    1352                 : 
    1353             120 :     ECWInitialize();
    1354                 : 
    1355                 : /* -------------------------------------------------------------------- */
    1356                 : /*      If we get a J2K_SUBFILE style name, convert it into the         */
    1357                 : /*      corresponding /vsisubfile/ path.                                */
    1358                 : /*                                                                      */
    1359                 : /*      From: J2K_SUBFILE:offset,size,filename                           */
    1360                 : /*      To: /vsisubfile/offset_size,filename                            */
    1361                 : /* -------------------------------------------------------------------- */
    1362             120 :     if (EQUALN(osFilename,"J2K_SUBFILE:",12))
    1363                 :     {
    1364               0 :         char** papszTokens = CSLTokenizeString2(osFilename.c_str()+12, ",", 0);
    1365               0 :         if (CSLCount(papszTokens) >= 2)
    1366                 :         {
    1367                 :             osFilename.Printf( "/vsisubfile/%s_%s,%s",
    1368               0 :                                papszTokens[0], papszTokens[1], papszTokens[2]);
    1369                 :         }
    1370                 :         else
    1371                 :         {
    1372                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1373               0 :                       "Failed to parse J2K_SUBFILE specification." );
    1374               0 :             CSLDestroy(papszTokens);
    1375               0 :             return NULL;
    1376                 :         }
    1377               0 :         CSLDestroy(papszTokens);
    1378                 :     }
    1379                 : 
    1380                 : /* -------------------------------------------------------------------- */
    1381                 : /*      Open the client interface.                                      */
    1382                 : /* -------------------------------------------------------------------- */
    1383             120 :     poFileView = OpenFileView( osFilename, false, bUsingCustomStream );
    1384             120 :     if( poFileView == NULL )
    1385               2 :         return NULL;
    1386                 : 
    1387                 : /* -------------------------------------------------------------------- */
    1388                 : /*      Create a corresponding GDALDataset.                             */
    1389                 : /* -------------------------------------------------------------------- */
    1390                 :     ECWDataset  *poDS;
    1391                 : 
    1392             118 :     poDS = new ECWDataset(bIsJPEG2000);
    1393             118 :     poDS->poFileView = poFileView;
    1394             118 :     poDS->eAccess = poOpenInfo->eAccess;
    1395                 : 
    1396                 :     // Disable .aux.xml writing for subfiles and such.  Unfortunately
    1397                 :     // this will also disable it in some cases where it might be 
    1398                 :     // applicable. 
    1399             118 :     if( bUsingCustomStream )
    1400              30 :         poDS->nPamFlags |= GPF_DISABLED;
    1401                 : 
    1402             118 :     poDS->bUsingCustomStream = bUsingCustomStream;
    1403                 : 
    1404                 : /* -------------------------------------------------------------------- */
    1405                 : /*      Fetch general file information.                                 */
    1406                 : /* -------------------------------------------------------------------- */
    1407             118 :     poDS->psFileInfo = poFileView->GetFileInfo();
    1408                 : 
    1409                 :     CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
    1410                 :               "       OriginXY=%g,%g  CellIncrementXY=%g,%g\n"
    1411                 :               "       ColorSpace=%d, eCellType=%d\n", 
    1412                 :               poDS->psFileInfo->nSizeX,
    1413                 :               poDS->psFileInfo->nSizeY,
    1414                 :               poDS->psFileInfo->nBands,
    1415                 :               poDS->psFileInfo->fOriginX,
    1416                 :               poDS->psFileInfo->fOriginY,
    1417                 :               poDS->psFileInfo->fCellIncrementX,
    1418                 :               poDS->psFileInfo->fCellIncrementY,
    1419                 :               (int) poDS->psFileInfo->eColorSpace,
    1420             118 :               (int) poDS->psFileInfo->eCellType );
    1421                 : 
    1422                 : /* -------------------------------------------------------------------- */
    1423                 : /*      Establish raster info.                                          */
    1424                 : /* -------------------------------------------------------------------- */
    1425             118 :     poDS->nRasterXSize = poDS->psFileInfo->nSizeX; 
    1426             118 :     poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
    1427                 : 
    1428                 : /* -------------------------------------------------------------------- */
    1429                 : /*      Establish the GDAL data type that corresponds.  A few NCS       */
    1430                 : /*      data types have no direct corresponding value in GDAL so we     */
    1431                 : /*      will coerce to something sufficiently similar.                  */
    1432                 : /* -------------------------------------------------------------------- */
    1433             118 :     poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
    1434             118 :     switch( poDS->psFileInfo->eCellType )
    1435                 :     {
    1436                 :         case NCSCT_UINT8:
    1437              96 :             poDS->eRasterDataType = GDT_Byte;
    1438              96 :             break;
    1439                 : 
    1440                 :         case NCSCT_UINT16:
    1441              10 :             poDS->eRasterDataType = GDT_UInt16;
    1442              10 :             break;
    1443                 : 
    1444                 :         case NCSCT_UINT32:
    1445                 :         case NCSCT_UINT64:
    1446               2 :             poDS->eRasterDataType = GDT_UInt32;
    1447               2 :             poDS->eNCSRequestDataType = NCSCT_UINT32;
    1448               2 :             break;
    1449                 : 
    1450                 :         case NCSCT_INT8:
    1451                 :         case NCSCT_INT16:
    1452               6 :             poDS->eRasterDataType = GDT_Int16;
    1453               6 :             poDS->eNCSRequestDataType = NCSCT_INT16;
    1454               6 :             break;
    1455                 : 
    1456                 :         case NCSCT_INT32:
    1457                 :         case NCSCT_INT64:
    1458               4 :             poDS->eRasterDataType = GDT_Int32;
    1459               4 :             poDS->eNCSRequestDataType = NCSCT_INT32;
    1460               4 :             break;
    1461                 : 
    1462                 :         case NCSCT_IEEE4:
    1463               0 :             poDS->eRasterDataType = GDT_Float32;
    1464               0 :             break;
    1465                 : 
    1466                 :         case NCSCT_IEEE8:
    1467               0 :             poDS->eRasterDataType = GDT_Float64;
    1468                 :             break;
    1469                 :     }
    1470                 : 
    1471                 : /* -------------------------------------------------------------------- */
    1472                 : /*      Create band information objects.                                */
    1473                 : /* -------------------------------------------------------------------- */
    1474             348 :     for( i=0; i < poDS->psFileInfo->nBands; i++ )
    1475             230 :         poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
    1476                 : 
    1477                 : /* -------------------------------------------------------------------- */
    1478                 : /*      Look for supporting coordinate system information.              */
    1479                 : /* -------------------------------------------------------------------- */
    1480             118 :     if( bIsJPEG2000 )
    1481                 :     {
    1482              86 :         GDALJP2Metadata oJP2Geo;
    1483              86 :         if ( oJP2Geo.ReadAndParse( osFilename ) )
    1484                 :         {
    1485              46 :             poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
    1486              46 :             poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
    1487                 :             memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
    1488              46 :                     sizeof(double) * 6 );
    1489              46 :             poDS->nGCPCount = oJP2Geo.nGCPCount;
    1490              46 :             poDS->pasGCPList = oJP2Geo.pasGCPList;
    1491              46 :             oJP2Geo.pasGCPList = NULL;
    1492              46 :             oJP2Geo.nGCPCount = 0;
    1493                 :         }
    1494                 : 
    1495              86 :         if (oJP2Geo.pszXMPMetadata)
    1496                 :         {
    1497                 :             char *apszMDList[2];
    1498               2 :             apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
    1499               2 :             apszMDList[1] = NULL;
    1500               2 :             poDS->SetMetadata(apszMDList, "xml:XMP");
    1501              86 :         }
    1502                 :     }
    1503                 :     else
    1504                 :     {
    1505              32 :         poDS->ECW2WKTProjection();
    1506                 :     }
    1507                 : 
    1508                 : /* -------------------------------------------------------------------- */
    1509                 : /*      Check for world file for ecw files.                             */
    1510                 : /* -------------------------------------------------------------------- */
    1511             118 :     if( !poDS->bGeoTransformValid 
    1512                 :         && EQUAL(CPLGetExtension(osFilename),"ecw") )
    1513                 :     {
    1514                 :         poDS->bGeoTransformValid |= 
    1515                 :             GDALReadWorldFile( osFilename, ".eww", 
    1516                 :                                poDS->adfGeoTransform )
    1517                 :             || GDALReadWorldFile( osFilename, ".ecww", 
    1518                 :                                   poDS->adfGeoTransform )
    1519                 :             || GDALReadWorldFile( osFilename, ".wld", 
    1520               0 :                                   poDS->adfGeoTransform );
    1521                 :     }
    1522                 : 
    1523                 : /* -------------------------------------------------------------------- */
    1524                 : /*      Initialize any PAM information.                                 */
    1525                 : /* -------------------------------------------------------------------- */
    1526             118 :     poDS->SetDescription( osFilename );
    1527             118 :     poDS->TryLoadXML();
    1528                 :     
    1529             118 :     return( poDS );
    1530                 : }
    1531                 : 
    1532                 : /************************************************************************/
    1533                 : /*                            GetGCPCount()                             */
    1534                 : /************************************************************************/
    1535                 : 
    1536              14 : int ECWDataset::GetGCPCount()
    1537                 : 
    1538                 : {
    1539              14 :     if( nGCPCount != 0 )
    1540               6 :         return nGCPCount;
    1541                 :     else
    1542               8 :         return GDALPamDataset::GetGCPCount();
    1543                 : }
    1544                 : 
    1545                 : /************************************************************************/
    1546                 : /*                          GetGCPProjection()                          */
    1547                 : /************************************************************************/
    1548                 : 
    1549               4 : const char *ECWDataset::GetGCPProjection()
    1550                 : 
    1551                 : {
    1552               4 :     if( nGCPCount > 0 )
    1553               4 :         return pszProjection;
    1554                 :     else
    1555               0 :         return GDALPamDataset::GetGCPProjection();
    1556                 : }
    1557                 : 
    1558                 : /************************************************************************/
    1559                 : /*                               GetGCP()                               */
    1560                 : /************************************************************************/
    1561                 : 
    1562               6 : const GDAL_GCP *ECWDataset::GetGCPs()
    1563                 : 
    1564                 : {
    1565               6 :     if( nGCPCount != 0 )
    1566               4 :         return pasGCPList;
    1567                 :     else
    1568               2 :         return GDALPamDataset::GetGCPs();
    1569                 : }
    1570                 : 
    1571                 : /************************************************************************/
    1572                 : /*                          GetProjectionRef()                          */
    1573                 : /*                                                                      */
    1574                 : /*      We let PAM coordinate system override the one stored inside     */
    1575                 : /*      our file.                                                       */
    1576                 : /************************************************************************/
    1577                 : 
    1578              86 : const char *ECWDataset::GetProjectionRef() 
    1579                 : 
    1580                 : {
    1581              86 :     const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
    1582                 : 
    1583              86 :     if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
    1584              56 :         return pszProjection;
    1585                 :     else
    1586              30 :         return pszPamPrj;
    1587                 : }
    1588                 : 
    1589                 : /************************************************************************/
    1590                 : /*                          GetGeoTransform()                           */
    1591                 : /*                                                                      */
    1592                 : /*      Let the PAM geotransform override the native one if it is       */
    1593                 : /*      available.                                                      */
    1594                 : /************************************************************************/
    1595                 : 
    1596              56 : CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
    1597                 : 
    1598                 : {
    1599              56 :     CPLErr eErr = GDALPamDataset::GetGeoTransform( padfTransform );
    1600                 : 
    1601              56 :     if( eErr != CE_None && bGeoTransformValid )
    1602                 :     {
    1603              46 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    1604              46 :         return( CE_None );
    1605                 :     }
    1606                 :     else
    1607              10 :         return eErr;
    1608                 : }
    1609                 : 
    1610                 : /************************************************************************/
    1611                 : /*                           GetMetadataItem()                          */
    1612                 : /************************************************************************/
    1613                 : 
    1614              26 : const char *ECWDataset::GetMetadataItem( const char * pszName,
    1615                 :                                          const char * pszDomain )
    1616                 : {
    1617              26 :     if (!bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") && pszName != NULL)
    1618                 :     {
    1619              12 :         if (EQUAL(pszName, "PROJ"))
    1620               4 :             return m_osProjCode.size() ? m_osProjCode.c_str() : "RAW";
    1621               8 :         if (EQUAL(pszName, "DATUM"))
    1622               4 :             return m_osDatumCode.size() ? m_osDatumCode.c_str() : "RAW";
    1623               4 :         if (EQUAL(pszName, "UNITS"))
    1624               4 :             return m_osUnitsCode.size() ? m_osUnitsCode.c_str() : "METERS";
    1625                 :     }
    1626              14 :     return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
    1627                 : }
    1628                 : 
    1629                 : /************************************************************************/
    1630                 : /*                            GetMetadata()                             */
    1631                 : /************************************************************************/
    1632                 : 
    1633              38 : char **ECWDataset::GetMetadata( const char *pszDomain )
    1634                 : 
    1635                 : {
    1636              38 :     if( !bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") )
    1637                 :     {
    1638               0 :         oECWMetadataList.Clear();
    1639               0 :         oECWMetadataList.AddString(CPLSPrintf("%s=%s", "PROJ", GetMetadataItem("PROJ", "ECW")));
    1640               0 :         oECWMetadataList.AddString(CPLSPrintf("%s=%s", "DATUM", GetMetadataItem("DATUM", "ECW")));
    1641               0 :         oECWMetadataList.AddString(CPLSPrintf("%s=%s", "UNITS", GetMetadataItem("UNITS", "ECW")));
    1642               0 :         return oECWMetadataList.List();
    1643                 :     }
    1644              38 :     else if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
    1645              38 :         return GDALPamDataset::GetMetadata( pszDomain );
    1646                 :     else
    1647               0 :         return papszGMLMetadata;
    1648                 : }
    1649                 : 
    1650                 : /************************************************************************/
    1651                 : /*                         ECW2WKTProjection()                          */
    1652                 : /*                                                                      */
    1653                 : /*      Set the dataset pszProjection string in OGC WKT format by       */
    1654                 : /*      looking up the ECW (GDT) coordinate system info in              */
    1655                 : /*      ecw_cs.dat support data file.                                   */
    1656                 : /*                                                                      */
    1657                 : /*      This code is likely still broken in some circumstances.  For    */
    1658                 : /*      instance, I haven't been careful about changing the linear      */
    1659                 : /*      projection parameters (false easting/northing) if the units     */
    1660                 : /*      is feet.  Lots of cases missing here, and in ecw_cs.dat.        */
    1661                 : /************************************************************************/
    1662                 : 
    1663              32 : void ECWDataset::ECW2WKTProjection()
    1664                 : 
    1665                 : {
    1666              32 :     if( psFileInfo == NULL )
    1667               0 :         return;
    1668                 : 
    1669                 : /* -------------------------------------------------------------------- */
    1670                 : /*      Capture Geotransform.                                           */
    1671                 : /*                                                                      */
    1672                 : /*      We will try to ignore the provided file information if it is    */
    1673                 : /*      origin (0,0) and pixel size (1,1).  I think sometimes I have    */
    1674                 : /*      also seen pixel increments of 0 on invalid datasets.            */
    1675                 : /* -------------------------------------------------------------------- */
    1676              32 :     if( psFileInfo->fOriginX != 0.0 
    1677                 :         || psFileInfo->fOriginY != 0.0 
    1678                 :         || (psFileInfo->fCellIncrementX != 0.0 
    1679                 :             && psFileInfo->fCellIncrementX != 1.0)
    1680                 :         || (psFileInfo->fCellIncrementY != 0.0 
    1681                 :             && psFileInfo->fCellIncrementY != 1.0) )
    1682                 :     {
    1683              32 :         bGeoTransformValid = TRUE;
    1684                 :         
    1685              32 :         adfGeoTransform[0] = psFileInfo->fOriginX;
    1686              32 :         adfGeoTransform[1] = psFileInfo->fCellIncrementX;
    1687              32 :         adfGeoTransform[2] = 0.0;
    1688                 :         
    1689              32 :         adfGeoTransform[3] = psFileInfo->fOriginY;
    1690              32 :         adfGeoTransform[4] = 0.0;
    1691              32 :         adfGeoTransform[5] = -fabs(psFileInfo->fCellIncrementY);
    1692                 :     }
    1693                 : 
    1694                 : /* -------------------------------------------------------------------- */
    1695                 : /*      do we have projection and datum?                                */
    1696                 : /* -------------------------------------------------------------------- */
    1697              32 :     CPLString osUnits = ECWTranslateFromCellSizeUnits(psFileInfo->eCellSizeUnits);
    1698                 : 
    1699                 :     CPLDebug( "ECW", "projection=%s, datum=%s, units=%s",
    1700                 :               psFileInfo->szProjection, psFileInfo->szDatum,
    1701              32 :               osUnits.c_str());
    1702                 : 
    1703              32 :     if( EQUAL(psFileInfo->szProjection,"RAW") )
    1704                 :         return;
    1705                 : 
    1706                 : /* -------------------------------------------------------------------- */
    1707                 : /*      Set projection if we have it.                                   */
    1708                 : /* -------------------------------------------------------------------- */
    1709              18 :     OGRSpatialReference oSRS;
    1710                 : 
    1711                 :     /* For backward-compatible with previous behaviour. Should we only */
    1712                 :     /* restrict to those 2 values ? */
    1713              18 :     if (psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_METERS &&
    1714                 :         psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_FEET)
    1715               0 :         osUnits = ECWTranslateFromCellSizeUnits(ECW_CELL_UNITS_METERS);
    1716                 : 
    1717              18 :     m_osDatumCode = psFileInfo->szDatum;
    1718              18 :     m_osProjCode = psFileInfo->szProjection;
    1719              18 :     m_osUnitsCode = osUnits;
    1720              18 :     if( oSRS.importFromERM( psFileInfo->szProjection, 
    1721                 :                             psFileInfo->szDatum, 
    1722                 :                             osUnits ) == OGRERR_NONE )
    1723                 :     {
    1724              18 :         oSRS.exportToWkt( &pszProjection );
    1725                 :     }
    1726                 : 
    1727              18 :     CPLErrorReset(); /* see #4187 */
    1728                 : }
    1729                 : 
    1730                 : /************************************************************************/
    1731                 : /*                        ECWTranslateFromWKT()                         */
    1732                 : /************************************************************************/
    1733                 : 
    1734              48 : int ECWTranslateFromWKT( const char *pszWKT,
    1735                 :                          char *pszProjection,
    1736                 :                          int nProjectionLen,
    1737                 :                          char *pszDatum,
    1738                 :                          int nDatumLen,
    1739                 :                          char *pszUnits)
    1740                 : 
    1741                 : {
    1742              48 :     OGRSpatialReference oSRS;
    1743              48 :     char *pszWKTIn = (char *) pszWKT;
    1744                 : 
    1745              48 :     strcpy( pszProjection, "RAW" );
    1746              48 :     strcpy( pszDatum, "RAW" );
    1747              48 :     strcpy( pszUnits, "METERS" );
    1748                 : 
    1749              48 :     if( pszWKT == NULL || strlen(pszWKT) == 0 )
    1750               2 :         return FALSE;
    1751                 :     
    1752              46 :     oSRS.importFromWkt( &pszWKTIn );
    1753                 :     
    1754              46 :     if( oSRS.IsLocal() )
    1755               0 :         return TRUE;
    1756                 : 
    1757                 : /* -------------------------------------------------------------------- */
    1758                 : /*      Do we have an overall EPSG number for this coordinate system?   */
    1759                 : /* -------------------------------------------------------------------- */
    1760              46 :     const char *pszAuthorityCode = NULL;
    1761              46 :     const char *pszAuthorityName = NULL;
    1762              46 :     UINT32 nEPSGCode = 0;
    1763                 : 
    1764              46 :     if( oSRS.IsProjected() )
    1765                 :     {
    1766              12 :         pszAuthorityCode =  oSRS.GetAuthorityCode( "PROJCS" );
    1767              12 :         pszAuthorityName =  oSRS.GetAuthorityName( "PROJCS" );
    1768                 :     }
    1769              34 :     else if( oSRS.IsGeographic() )
    1770                 :     {
    1771              34 :         pszAuthorityCode =  oSRS.GetAuthorityCode( "GEOGCS" );
    1772              34 :         pszAuthorityName =  oSRS.GetAuthorityName( "GEOGCS" );
    1773                 :     }
    1774                 : 
    1775              46 :     if( pszAuthorityName != NULL && EQUAL(pszAuthorityName,"EPSG") 
    1776                 :         && pszAuthorityCode != NULL && atoi(pszAuthorityCode) > 0 )
    1777              36 :         nEPSGCode = (UINT32) atoi(pszAuthorityCode);
    1778                 : 
    1779              46 :     if( nEPSGCode != 0 )
    1780                 :     {
    1781              36 :         char *pszEPSGProj = NULL, *pszEPSGDatum = NULL;
    1782              36 :         CNCSError oErr;
    1783                 : 
    1784                 :         oErr = 
    1785                 :             CNCSJP2FileView::GetProjectionAndDatum( atoi(pszAuthorityCode), 
    1786              36 :                                                  &pszEPSGProj, &pszEPSGDatum );
    1787                 : 
    1788                 :         CPLDebug( "ECW", "GetGDTProjDat(%d) = %s/%s", 
    1789              36 :                   atoi(pszAuthorityCode), pszEPSGProj, pszEPSGDatum );
    1790                 : 
    1791              36 :         if( oErr.GetErrorNumber() == NCS_SUCCESS
    1792                 :             && pszEPSGProj != NULL && pszEPSGDatum != NULL )
    1793                 :         {
    1794              36 :             strncpy( pszProjection, pszEPSGProj, nProjectionLen );
    1795              36 :             strncpy( pszDatum, pszEPSGDatum, nDatumLen );
    1796              36 :             pszProjection[nProjectionLen - 1] = 0;
    1797              36 :             pszDatum[nDatumLen - 1] = 0;
    1798              36 :             NCSFree( pszEPSGProj );
    1799              36 :             NCSFree( pszEPSGDatum );
    1800              36 :             return TRUE;
    1801                 :         }
    1802                 : 
    1803               0 :         NCSFree( pszEPSGProj );
    1804               0 :         NCSFree( pszEPSGDatum );
    1805                 : 
    1806                 :     }
    1807                 : 
    1808                 : /* -------------------------------------------------------------------- */
    1809                 : /*      Fallback to translating based on the ecw_cs.wkt file, and       */
    1810                 : /*      various jiffy rules.                                            */
    1811                 : /* -------------------------------------------------------------------- */
    1812                 : 
    1813              10 :     return oSRS.exportToERM( pszProjection, pszDatum, pszUnits ) == OGRERR_NONE;
    1814                 : }
    1815                 : 
    1816                 : /************************************************************************/
    1817                 : /*                    ECWTranslateToCellSizeUnits()                     */
    1818                 : /************************************************************************/
    1819                 : 
    1820              50 : CellSizeUnits ECWTranslateToCellSizeUnits(const char* pszUnits)
    1821                 : {
    1822              50 :     if (EQUAL(pszUnits, "METERS"))
    1823              46 :         return ECW_CELL_UNITS_METERS;
    1824               4 :     else if (EQUAL(pszUnits, "DEGREES"))
    1825               0 :         return ECW_CELL_UNITS_DEGREES;
    1826               4 :     else if (EQUAL(pszUnits, "FEET"))
    1827               4 :         return ECW_CELL_UNITS_FEET;
    1828               0 :     else if (EQUAL(pszUnits, "UNKNOWN"))
    1829               0 :         return ECW_CELL_UNITS_UNKNOWN;
    1830               0 :     else if (EQUAL(pszUnits, "INVALID"))
    1831               0 :         return ECW_CELL_UNITS_INVALID;
    1832                 :     else
    1833                 :     {
    1834               0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized value for UNITS : %s", pszUnits);
    1835               0 :         return ECW_CELL_UNITS_INVALID;
    1836                 :     }
    1837                 : }
    1838                 : 
    1839                 : /************************************************************************/
    1840                 : /*                     ECWTranslateFromCellSizeUnits()                  */
    1841                 : /************************************************************************/
    1842                 : 
    1843              84 : const char* ECWTranslateFromCellSizeUnits(CellSizeUnits eUnits)
    1844                 : {
    1845              84 :     if (eUnits == ECW_CELL_UNITS_METERS)
    1846              76 :         return "METERS";
    1847               8 :     else if (eUnits == ECW_CELL_UNITS_DEGREES)
    1848               0 :         return "DEGREES";
    1849               8 :     else if (eUnits == ECW_CELL_UNITS_FEET)
    1850               8 :         return "FEET";
    1851               0 :     else if (eUnits == ECW_CELL_UNITS_UNKNOWN)
    1852               0 :         return "UNKNOWN";
    1853                 :     else
    1854               0 :         return "INVALID";
    1855                 : }
    1856                 : 
    1857                 : #endif /* def FRMT_ecw */
    1858                 : 
    1859                 : /************************************************************************/
    1860                 : /*                           ECWInitialize()                            */
    1861                 : /*                                                                      */
    1862                 : /*      Initialize NCS library.  We try to defer this as late as        */
    1863                 : /*      possible since de-initializing it seems to be expensive/slow    */
    1864                 : /*      on some system.                                                 */
    1865                 : /************************************************************************/
    1866                 : 
    1867             220 : void ECWInitialize()
    1868                 : 
    1869                 : {
    1870             220 :     CPLMutexHolder oHolder( &hECWDatasetMutex );
    1871                 : 
    1872             220 :     if( bNCSInitialized )
    1873                 :         return;
    1874                 : 
    1875               6 :     NCSecwInit();
    1876               6 :     bNCSInitialized = TRUE;
    1877                 : 
    1878                 : /* -------------------------------------------------------------------- */
    1879                 : /*      This will disable automatic conversion of YCbCr to RGB by       */
    1880                 : /*      the toolkit.                                                    */
    1881                 : /* -------------------------------------------------------------------- */
    1882               6 :     if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
    1883               0 :         NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
    1884                 : 
    1885                 : /* -------------------------------------------------------------------- */
    1886                 : /*      Initialize cache memory limit.  Default is apparently 1/4 RAM.  */
    1887                 : /* -------------------------------------------------------------------- */
    1888                 :     const char *pszEcwCacheSize = 
    1889               6 :         CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
    1890               6 :     if( pszEcwCacheSize == NULL )
    1891               6 :         pszEcwCacheSize = CPLGetConfigOption("ECW_CACHE_MAXMEM",NULL);
    1892                 : 
    1893               6 :     if( pszEcwCacheSize != NULL )
    1894               0 :         NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, (UINT32) atoi(pszEcwCacheSize) );
    1895                 : 
    1896                 : /* -------------------------------------------------------------------- */
    1897                 : /*      Allow configuration of a local cache based on configuration     */
    1898                 : /*      options.  Setting the location turns things on.                 */
    1899                 : /* -------------------------------------------------------------------- */
    1900                 :     const char *pszOpt;
    1901                 : 
    1902                 : #if ECWSDK_VERSION >= 40
    1903                 :     pszOpt = CPLGetConfigOption( "ECWP_CACHE_SIZE_MB", NULL );
    1904                 :     if( pszOpt )
    1905                 :         NCSecwSetConfig( NCSCFG_ECWP_CACHE_SIZE_MB, (INT32) atoi( pszOpt ) );
    1906                 : 
    1907                 :     pszOpt = CPLGetConfigOption( "ECWP_CACHE_LOCATION", NULL );
    1908                 :     if( pszOpt )
    1909                 :     {
    1910                 :         NCSecwSetConfig( NCSCFG_ECWP_CACHE_LOCATION, pszOpt );
    1911                 :         NCSecwSetConfig( NCSCFG_ECWP_CACHE_ENABLED, (BOOLEAN) TRUE );
    1912                 :     }
    1913                 : #endif
    1914                 : 
    1915                 : /* -------------------------------------------------------------------- */
    1916                 : /*      Various other configuration items.                              */
    1917                 : /* -------------------------------------------------------------------- */
    1918               6 :     pszOpt = CPLGetConfigOption( "ECWP_BLOCKING_TIME_MS", NULL );
    1919               6 :     if( pszOpt )
    1920                 :         NCSecwSetConfig( NCSCFG_BLOCKING_TIME_MS, 
    1921               0 :                          (NCSTimeStampMs) atoi(pszOpt) );
    1922                 : 
    1923                 :     // I believe 10s means we wait for complete data back from
    1924                 :     // ECWP almost all the time which is good for our blocking model.
    1925               6 :     pszOpt = CPLGetConfigOption( "ECWP_REFRESH_TIME_MS", "10000" );
    1926               6 :     if( pszOpt )
    1927                 :         NCSecwSetConfig( NCSCFG_REFRESH_TIME_MS, 
    1928               6 :                          (NCSTimeStampMs) atoi(pszOpt) );
    1929                 : 
    1930               6 :     pszOpt = CPLGetConfigOption( "ECW_TEXTURE_DITHER", NULL );
    1931               6 :     if( pszOpt )
    1932                 :         NCSecwSetConfig( NCSCFG_TEXTURE_DITHER, 
    1933               0 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    1934                 : 
    1935                 : 
    1936               6 :     pszOpt = CPLGetConfigOption( "ECW_FORCE_FILE_REOPEN", NULL );
    1937               6 :     if( pszOpt )
    1938                 :         NCSecwSetConfig( NCSCFG_FORCE_FILE_REOPEN, 
    1939               0 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    1940                 : 
    1941               6 :     pszOpt = CPLGetConfigOption( "ECW_CACHE_MAXOPEN", NULL );
    1942               6 :     if( pszOpt )
    1943               0 :         NCSecwSetConfig( NCSCFG_CACHE_MAXOPEN, (UINT32) atoi(pszOpt) );
    1944                 : 
    1945                 : #if ECWSDK_VERSION >= 40
    1946                 :     pszOpt = CPLGetConfigOption( "ECW_AUTOGEN_J2I", NULL );
    1947                 :     if( pszOpt )
    1948                 :         NCSecwSetConfig( NCSCFG_JP2_AUTOGEN_J2I, 
    1949                 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    1950                 : 
    1951                 :     pszOpt = CPLGetConfigOption( "ECW_OPTIMIZE_USE_NEAREST_NEIGHBOUR", NULL );
    1952                 :     if( pszOpt )
    1953                 :         NCSecwSetConfig( NCSCFG_OPTIMIZE_USE_NEAREST_NEIGHBOUR, 
    1954                 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    1955                 : 
    1956                 : 
    1957                 :     pszOpt = CPLGetConfigOption( "ECW_RESILIENT_DECODING", NULL );
    1958                 :     if( pszOpt )
    1959                 :         NCSecwSetConfig( NCSCFG_RESILIENT_DECODING, 
    1960                 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    1961                 : #endif
    1962                 : }
    1963                 : 
    1964                 : /************************************************************************/
    1965                 : /*                         GDALDeregister_ECW()                         */
    1966                 : /************************************************************************/
    1967                 : 
    1968            1057 : void GDALDeregister_ECW( GDALDriver * )
    1969                 : 
    1970                 : {
    1971                 :     /* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
    1972                 :     /* Not worth it */
    1973                 : #ifdef notdef
    1974                 :     if( bNCSInitialized )
    1975                 :     {
    1976                 :         bNCSInitialized = FALSE;
    1977                 :         NCSecwShutdown();
    1978                 :     }
    1979                 : 
    1980                 :     if( hECWDatasetMutex != NULL )
    1981                 :     {
    1982                 :         CPLDestroyMutex( hECWDatasetMutex );
    1983                 :         hECWDatasetMutex = NULL;
    1984                 :     }
    1985                 : #endif
    1986            1057 : }
    1987                 : 
    1988                 : /************************************************************************/
    1989                 : /*                          GDALRegister_ECW()                        */
    1990                 : /************************************************************************/
    1991                 : 
    1992            1135 : void GDALRegister_ECW()
    1993                 : 
    1994                 : {
    1995                 : #ifdef FRMT_ecw 
    1996                 :     GDALDriver  *poDriver;
    1997                 : 
    1998            1135 :     if (! GDAL_CHECK_VERSION("ECW driver"))
    1999               0 :         return;
    2000                 : 
    2001            1135 :     if( GDALGetDriverByName( "ECW" ) == NULL )
    2002                 :     {
    2003            1093 :         poDriver = new GDALDriver();
    2004                 :         
    2005            1093 :         poDriver->SetDescription( "ECW" );
    2006                 : 
    2007            1093 :         CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
    2008                 : 
    2009                 : #ifdef NCS_ECWSDK_VERSION_STRING
    2010                 :         osLongName += NCS_ECWSDK_VERSION_STRING;
    2011                 : #else
    2012            1093 :         osLongName += "3.x";
    2013                 : #endif        
    2014            1093 :         osLongName += ")";
    2015                 : 
    2016            1093 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
    2017                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2018            1093 :                                    "frmt_ecw.html" );
    2019            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
    2020                 :         
    2021            1093 :         poDriver->pfnIdentify = ECWDataset::IdentifyECW;
    2022            1093 :         poDriver->pfnOpen = ECWDataset::OpenECW;
    2023            1093 :         poDriver->pfnUnloadDriver = GDALDeregister_ECW;
    2024                 : #ifdef HAVE_COMPRESS
    2025                 : // The create method seems not to work properly.
    2026                 : //        poDriver->pfnCreate = ECWCreateECW;  
    2027            1093 :         poDriver->pfnCreateCopy = ECWCreateCopyECW;
    2028                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2029            1093 :                                    "Byte" );
    2030                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    2031                 : "<CreationOptionList>"
    2032                 : "   <Option name='TARGET' type='float' description='Compression Percentage' />"
    2033                 : "   <Option name='PROJ' type='string' description='ECW Projection Name'/>"
    2034                 : "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
    2035                 : 
    2036                 : #if ECWSDK_VERSION < 40
    2037                 : "   <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
    2038                 : #else
    2039                 : "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
    2040                 : "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
    2041                 : #endif
    2042                 : 
    2043            1093 : "</CreationOptionList>" );
    2044                 : #else
    2045                 :         /* In read-only mode, we support VirtualIO. This is not the case */
    2046                 :         /* for ECWCreateCopyECW() */
    2047                 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2048                 : #endif
    2049                 : 
    2050            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2051                 :     }
    2052                 : #endif /* def FRMT_ecw */
    2053                 : }
    2054                 : 
    2055                 : /************************************************************************/
    2056                 : /*                      GDALRegister_ECW_JP2ECW()                       */
    2057                 : /*                                                                      */
    2058                 : /*      This function exists so that when built as a plugin, there      */
    2059                 : /*      is a function that will register both drivers.                  */
    2060                 : /************************************************************************/
    2061                 : 
    2062               0 : void GDALRegister_ECW_JP2ECW()
    2063                 : 
    2064                 : {
    2065               0 :     GDALRegister_ECW();
    2066               0 :     GDALRegister_JP2ECW();
    2067               0 : }
    2068                 : 
    2069                 : /************************************************************************/
    2070                 : /*                     ECWDatasetOpenJPEG2000()                         */
    2071                 : /************************************************************************/
    2072              34 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
    2073                 : {
    2074              34 :     return ECWDataset::OpenJPEG2000(poOpenInfo);
    2075                 : }
    2076                 : 
    2077                 : /************************************************************************/
    2078                 : /*                        GDALRegister_JP2ECW()                         */
    2079                 : /************************************************************************/
    2080            1135 : void GDALRegister_JP2ECW()
    2081                 : 
    2082                 : {
    2083                 : #ifdef FRMT_ecw 
    2084                 :     GDALDriver  *poDriver;
    2085                 : 
    2086            1135 :     if (! GDAL_CHECK_VERSION("JP2ECW driver"))
    2087               0 :         return;
    2088                 : 
    2089            1135 :     if( GDALGetDriverByName( "JP2ECW" ) == NULL )
    2090                 :     {
    2091            1093 :         poDriver = new GDALDriver();
    2092                 :         
    2093            1093 :         poDriver->SetDescription( "JP2ECW" );
    2094                 : 
    2095            1093 :         CPLString osLongName = "ERDAS JPEG2000 (SDK ";
    2096                 : 
    2097                 : #ifdef NCS_ECWSDK_VERSION_STRING
    2098                 :         osLongName += NCS_ECWSDK_VERSION_STRING;
    2099                 : #else
    2100            1093 :         osLongName += "3.x";
    2101                 : #endif        
    2102            1093 :         osLongName += ")";
    2103                 : 
    2104            1093 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
    2105                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2106            1093 :                                    "frmt_jp2ecw.html" );
    2107            1093 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
    2108            1093 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2109                 :         
    2110            1093 :         poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
    2111            1093 :         poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
    2112                 : #ifdef HAVE_COMPRESS
    2113            1093 :         poDriver->pfnCreate = ECWCreateJPEG2000;
    2114            1093 :         poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
    2115                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2116            1093 :                                    "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
    2117                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    2118                 : "<CreationOptionList>"
    2119                 : "   <Option name='TARGET' type='float' description='Compression Percentage' />"
    2120                 : "   <Option name='PROJ' type='string' description='ECW Projection Name'/>"
    2121                 : "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
    2122                 : "   <Option name='UNITS' type='string-select' description='ECW Projection Units'>"
    2123                 : "       <Value>METERS</Value>"
    2124                 : "       <Value>FEET</Value>"
    2125                 : "   </Option>"
    2126                 : 
    2127                 : #if ECWSDK_VERSION < 40
    2128                 : "   <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
    2129                 : #else
    2130                 : "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
    2131                 : "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
    2132                 : #endif
    2133                 : 
    2134                 : "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
    2135                 : "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
    2136                 : "   <Option name='PROFILE' type='string-select'>"
    2137                 : "       <Value>BASELINE_0</Value>"
    2138                 : "       <Value>BASELINE_1</Value>"
    2139                 : "       <Value>BASELINE_2</Value>"
    2140                 : "       <Value>NPJE</Value>"
    2141                 : "       <Value>EPJE</Value>"
    2142                 : "   </Option>"
    2143                 : "   <Option name='PROGRESSION' type='string-select'>"
    2144                 : "       <Value>LRCP</Value>"
    2145                 : "       <Value>RLCP</Value>"
    2146                 : "       <Value>RPCL</Value>"
    2147                 : "   </Option>"
    2148                 : "   <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
    2149                 : "   <Option name='LEVELS' type='int'/>"
    2150                 : "   <Option name='LAYERS' type='int'/>"
    2151                 : "   <Option name='PRECINCT_WIDTH' type='int'/>"
    2152                 : "   <Option name='PRECINCT_HEIGHT' type='int'/>"
    2153                 : "   <Option name='TILE_WIDTH' type='int'/>"
    2154                 : "   <Option name='TILE_HEIGHT' type='int'/>"
    2155                 : "   <Option name='INCLUDE_SOP' type='boolean'/>"
    2156                 : "   <Option name='INCLUDE_EPH' type='boolean'/>"
    2157                 : "   <Option name='DECOMPRESS_LAYERS' type='int'/>"
    2158                 : "   <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
    2159            1093 : "</CreationOptionList>" );
    2160                 : #endif
    2161                 : 
    2162            1093 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2163                 :     }
    2164                 : #endif /* def FRMT_ecw */
    2165            4029 : }

Generated by: LCOV version 1.7