LCOV - code coverage report
Current view: directory - frmts/ecw - ecwdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 782 644 82.4 %
Date: 2012-12-26 Functions: 53 44 83.0 %

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

Generated by: LCOV version 1.7