LCOV - code coverage report
Current view: directory - frmts/ecw - ecwdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 875 723 82.6 %
Date: 2013-03-30 Functions: 55 47 85.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: ecwdataset.cpp 25804 2013-03-25 18:50:26Z 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 25804 2013-03-25 18:50:26Z 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                 :     {
     100              37 :         eBandInterp = GCI_GrayIndex;
     101                 :         //we could also have alpha band. 
     102              37 :         if ( strcmp(poDS->psFileInfo->pBands[nBand-1].szDesc, NCS_BANDDESC_AllOpacity) == 0 ||  strcmp(poDS->psFileInfo->pBands[nBand-1].szDesc, NCS_BANDDESC_GreyscaleOpacity) ){
     103              37 :             eBandInterp = GCI_AlphaBand;
     104                 :         }
     105             200 :     }else if (poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND ){
     106              28 :         eBandInterp = ECWGetColorInterpretationByName(poDS->psFileInfo->pBands[nBand-1].szDesc);
     107             172 :     }else if (poDS->psFileInfo->eColorSpace == NCSCS_sRGB){
     108                 :         //color interpretation is the most important. 
     109             172 :         if( nBand == 1 )
     110              57 :                 eBandInterp = GCI_RedBand;
     111             115 :             else if( nBand == 2 )
     112              57 :                 eBandInterp = GCI_GreenBand;
     113              58 :             else if( nBand == 3 )
     114              57 :                 eBandInterp = GCI_BlueBand;
     115               1 :             else if (nBand == 4){
     116               1 :                 eBandInterp = GCI_AlphaBand;
     117                 :             }else {
     118               0 :                    eBandInterp = GCI_Undefined;
     119                 :             }
     120                 :     }
     121               0 :     else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
     122                 :     {
     123               0 :         if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
     124                 :         {
     125               0 :             if( nBand == 1 )
     126               0 :                 eBandInterp = GCI_RedBand;
     127               0 :             else if( nBand == 2 )
     128               0 :                 eBandInterp = GCI_GreenBand;
     129               0 :             else if( nBand == 3 )
     130               0 :                 eBandInterp = GCI_BlueBand;
     131                 :             else
     132               0 :                 eBandInterp = GCI_Undefined;
     133                 :         }
     134                 :         else
     135                 :         {
     136               0 :             if( nBand == 1 )
     137               0 :                 eBandInterp = GCI_YCbCr_YBand;
     138               0 :             else if( nBand == 2 )
     139               0 :                 eBandInterp = GCI_YCbCr_CbBand;
     140               0 :             else if( nBand == 3 )
     141               0 :                 eBandInterp = GCI_YCbCr_CrBand;
     142                 :             else
     143               0 :                 eBandInterp = GCI_Undefined;
     144                 :         }
     145                 :     }
     146                 :     else
     147               0 :         eBandInterp = GCI_Undefined;
     148                 : 
     149                 : /* -------------------------------------------------------------------- */
     150                 : /*      If this is the base level, create a set of overviews.           */
     151                 : /* -------------------------------------------------------------------- */
     152             237 :     if( iOverview == -1 )
     153                 :     {
     154                 :         int i;
     155             237 :         for( i = 0; 
     156                 :              nRasterXSize / (1 << (i+1)) > 128 
     157                 :                  && nRasterYSize / (1 << (i+1)) > 128;
     158                 :              i++ )
     159                 :         {
     160              99 :             apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i ) );
     161                 :         }
     162                 :     }
     163                 : 
     164             237 :     if( (poDS->psFileInfo->pBands[nBand-1].nBits % 8) != 0 )
     165                 :         SetMetadataItem("NBITS",
     166               4 :                         CPLString().Printf("%d",poDS->psFileInfo->pBands[nBand-1].nBits),
     167               4 :                         "IMAGE_STRUCTURE" );
     168             237 : }
     169                 : 
     170                 : /************************************************************************/
     171                 : /*                          ~ECWRasterBand()                           */
     172                 : /************************************************************************/
     173                 : 
     174             237 : ECWRasterBand::~ECWRasterBand()
     175                 : 
     176                 : {
     177             237 :     FlushCache();
     178                 : 
     179             573 :     while( apoOverviews.size() > 0 )
     180                 :     {
     181              99 :         delete apoOverviews.back();
     182              99 :         apoOverviews.pop_back();
     183                 :     }
     184             237 : }
     185                 : 
     186                 : /************************************************************************/
     187                 : /*                            GetOverview()                             */
     188                 : /************************************************************************/
     189                 : 
     190               2 : GDALRasterBand *ECWRasterBand::GetOverview( int iOverview )
     191                 : 
     192                 : {
     193               2 :     if( iOverview >= 0 && iOverview < (int) apoOverviews.size() )
     194               2 :         return apoOverviews[iOverview];
     195                 :     else
     196               0 :         return NULL;
     197                 : }
     198                 : 
     199                 : /************************************************************************/
     200                 : /*                       GetColorInterpretation()                       */
     201                 : /************************************************************************/
     202                 : 
     203              67 : GDALColorInterp ECWRasterBand::GetColorInterpretation()
     204                 : 
     205                 : {
     206              67 :     return eBandInterp;
     207                 : }
     208                 : 
     209                 : /************************************************************************/
     210                 : /*                       SetColorInterpretation()                       */
     211                 : /*                                                                      */
     212                 : /*      This would normally just be used by folks using the ECW code    */
     213                 : /*      to read JP2 streams in other formats (such as NITF) and         */
     214                 : /*      providing their own color interpretation regardless of what     */
     215                 : /*      ECW might think the stream itself says.                         */
     216                 : /************************************************************************/
     217                 : 
     218              12 : CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
     219                 : 
     220                 : {
     221              12 :     eBandInterp = eNewInterp;
     222                 : 
     223              12 :     return CE_None;
     224                 : }
     225                 : 
     226                 : /************************************************************************/
     227                 : /*                             AdviseRead()                             */
     228                 : /************************************************************************/
     229                 : 
     230               0 : CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
     231                 :                                   int nBufXSize, int nBufYSize, 
     232                 :                                   GDALDataType eDT, 
     233                 :                                   char **papszOptions )
     234                 : {
     235               0 :     int nResFactor = 1 << (iOverview+1);
     236                 :     
     237                 :     return poGDS->AdviseRead( nXOff * nResFactor, 
     238                 :                               nYOff * nResFactor, 
     239                 :                               nXSize * nResFactor, 
     240                 :                               nYSize * nResFactor, 
     241                 :                               nBufXSize, nBufYSize, eDT, 
     242               0 :                               1, &nBand, papszOptions );
     243                 : }
     244                 : 
     245                 : //statistics support: 
     246                 : #if ECWSDK_VERSION >= 50
     247                 : 
     248                 : /************************************************************************/
     249                 : /*                       GetDefaultHistogram()                          */
     250                 : /************************************************************************/
     251                 : 
     252                 : CPLErr ECWRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
     253                 :     int *pnBuckets, int ** ppanHistogram,
     254                 :     int bForce,
     255                 :     GDALProgressFunc f, void *pProgressData){
     256                 : 
     257                 :         int bForceCoalesced = bForce;
     258                 :         // If file version is smaller than 3, there will be no statistics in the file. But if it is version 3 or higher we don't want underlying implementation to compute histogram
     259                 :         // so we set bForceCoalesced to FALSE. 
     260                 :         if (poGDS->psFileInfo->nFormatVersion >= 3){
     261                 :             bForceCoalesced = FALSE;
     262                 :         }
     263                 :         // We check if we have PAM histogram. If we have them we return them. This will allow to override statistics stored in the file. 
     264                 :         CPLErr pamError =  GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram, bForceCoalesced, f, pProgressData);
     265                 :         if ( pamError == CE_None || poGDS->psFileInfo->nFormatVersion<3 ){
     266                 :             return pamError;
     267                 :         }
     268                 : 
     269                 :         NCS::CError error = poGDS->StatisticsEnsureInitialized();
     270                 :         if (!error.Success()){
     271                 :             CPLError( CE_Warning, CPLE_AppDefined,
     272                 :                 "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::GetDefaultHistogram. " );
     273                 :             return CE_Failure;
     274                 :         }
     275                 :         GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
     276                 :         if ( poGDS->pStatistics != NULL ){
     277                 :             NCSBandStats& bandStats = poGDS->pStatistics->BandsStats[nBand-1];
     278                 :             if ( bandStats.Histogram != NULL && bandStats.nHistBucketCount > 0 ){
     279                 :                 *pnBuckets = bandStats.nHistBucketCount;
     280                 :                 *ppanHistogram = (int *)VSIMalloc(bandStats.nHistBucketCount *sizeof(int));
     281                 :                 for (size_t i = 0; i < bandStats.nHistBucketCount; i++){
     282                 :                     (*ppanHistogram)[i] = (int) bandStats.Histogram[i];
     283                 :                 }
     284                 :             }else{
     285                 :                 //no default histogram in file. We push it down for the logic of computation/returning warning. 
     286                 :                 return GDALRasterBand::GetDefaultHistogram(pdfMin,pdfMax,pnBuckets,ppanHistogram,bForce,f, pProgressData);
     287                 :             }
     288                 :             if ( pdfMin != NULL ){
     289                 :                 *pdfMin = bandStats.fMinHist;
     290                 :             }
     291                 :             if ( pdfMax != NULL ){
     292                 :                 *pdfMax = bandStats.fMaxHist;
     293                 :             }
     294                 :             return CE_None;
     295                 :         }else {
     296                 :             //no default histogram in file. We push it down for the logic of computation/returning warning. 
     297                 :             return GDALRasterBand::GetDefaultHistogram(pdfMin,pdfMax,pnBuckets,ppanHistogram,bForce,f, pProgressData);
     298                 :         }
     299                 : }
     300                 : 
     301                 : /************************************************************************/
     302                 : /*                       SetDefaultHistogram()                          */
     303                 : /************************************************************************/
     304                 : 
     305                 : CPLErr ECWRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
     306                 :     int nBuckets, int *panHistogram ){
     307                 :         //Only version 3 supports saving statistics. 
     308                 :         if (poGDS->psFileInfo->nFormatVersion < 3){
     309                 :             return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
     310                 :         }
     311                 :         
     312                 :         //determine if there are statistics in PAM file. 
     313                 :         double dummy;
     314                 :         int dummy_i;
     315                 :         int *dummy_histogram;
     316                 :         bool hasPAMDefaultHistogram = GDALPamRasterBand::GetDefaultHistogram(&dummy, &dummy, &dummy_i, &dummy_histogram, FALSE, NULL, NULL) == CE_None;
     317                 :         if (hasPAMDefaultHistogram){
     318                 :             VSIFree(dummy_histogram);
     319                 :         }
     320                 : 
     321                 :         //ECW SDK ignores statistics for opacity bands. So we need to compute number of bands without opacity.
     322                 :         GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
     323                 :         UINT32 bucketCounts[256];
     324                 :         std::fill_n(bucketCounts, nStatsBandCount, 0);
     325                 :         bucketCounts[nStatsBandIndex] = nBuckets;
     326                 : 
     327                 :         NCS::CError error = poGDS->StatisticsEnsureInitialized();
     328                 :         if (!error.Success()){
     329                 :             CPLError( CE_Warning, CPLE_AppDefined,
     330                 :                 "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::SetDefaultHistogram. Default histogram will be written to PAM. " );
     331                 :             return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
     332                 :         }
     333                 :         
     334                 :         NCSFileStatistics *pStatistics = poGDS->pStatistics;
     335                 : 
     336                 :         if (pStatistics == NULL){
     337                 :             error = NCSEcwInitStatistics(&pStatistics, nStatsBandCount, bucketCounts);
     338                 :             poGDS->bStatisticsDirty = TRUE;
     339                 :             poGDS->pStatistics = pStatistics;
     340                 :             if (!error.Success()){
     341                 :                 CPLError( CE_Warning, CPLE_AppDefined,
     342                 :                          "NCSEcwInitStatistics failed in ECWRasterBand::SetDefaultHistogram." );
     343                 :                 return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
     344                 :             }
     345                 :             //no error statistics properly initialized but there were no statistics previously. 
     346                 :         }else{
     347                 :             //is there a room for our band already? 
     348                 :             //This should account for following cases: 
     349                 :             //1. Existing histogram (for this or different band) has smaller bucket count. 
     350                 :             //2. There is no existing histogram but statistics are set for one or more bands (pStatistics->nHistBucketCounts is zero). 
     351                 :             if (pStatistics->BandsStats[nStatsBandIndex].nHistBucketCount != nBuckets){
     352                 :                 //no. There is no room. We need more!
     353                 :                 NCSFileStatistics *pNewStatistics = NULL;
     354                 :                 for (size_t i=0;i<pStatistics->nNumberOfBands;i++){
     355                 :                     bucketCounts[i] = pStatistics->BandsStats[i].nHistBucketCount;
     356                 :                 }
     357                 :                 bucketCounts[nStatsBandIndex] = nBuckets;
     358                 :                 if (nBuckets < (int)pStatistics->BandsStats[nStatsBandIndex].nHistBucketCount){
     359                 :                     pStatistics->BandsStats[nStatsBandIndex].nHistBucketCount = nBuckets;
     360                 :                 }
     361                 :                 error = NCSEcwInitStatistics(&pNewStatistics, nStatsBandCount, bucketCounts);
     362                 :                 if (!error.Success()){
     363                 :                     CPLError( CE_Warning, CPLE_AppDefined,
     364                 :                              "NCSEcwInitStatistics failed in ECWRasterBand::SetDefaultHistogram (realocate)." );
     365                 :                     return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
     366                 :                 }
     367                 :                 //we need to copy existing statistics.
     368                 :                 error = NCSEcwCopyStatistics(&pNewStatistics, pStatistics);
     369                 :                 if (!error.Success()){
     370                 :                     CPLError( CE_Warning, CPLE_AppDefined,
     371                 :                         "NCSEcwCopyStatistics failed in ECWRasterBand::SetDefaultHistogram." );
     372                 :                     NCSEcwFreeStatistics(pNewStatistics);
     373                 :                     return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
     374                 :                 }
     375                 :                 pNewStatistics->nNumberOfBands = nStatsBandCount;
     376                 :                 NCSEcwFreeStatistics(pStatistics);
     377                 :                 pStatistics = pNewStatistics;
     378                 :                 poGDS->pStatistics = pStatistics;
     379                 :                 poGDS->bStatisticsDirty = TRUE;
     380                 :             }
     381                 :         }
     382                 : 
     383                 :         //at this point we have allocated statistics structure.
     384                 :         pStatistics->BandsStats[nStatsBandIndex].fMinHist = (IEEE4) dfMin;
     385                 :         pStatistics->BandsStats[nStatsBandIndex].fMaxHist = (IEEE4) dfMax;
     386                 :         for (int i=0;i<nBuckets;i++){
     387                 :             pStatistics->BandsStats[nStatsBandIndex].Histogram[i] = (UINT64)panHistogram[i];
     388                 :         }
     389                 :         
     390                 :         if (hasPAMDefaultHistogram){
     391                 :             CPLError( CE_Debug, CPLE_AppDefined,
     392                 :                         "PAM default histogram will be overwritten." );
     393                 :             return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
     394                 :         }
     395                 :         return CE_None;
     396                 : }
     397                 : 
     398                 : /************************************************************************/
     399                 : /*                   GetBandIndexAndCountForStatistics()                */
     400                 : /************************************************************************/
     401                 : 
     402                 : void ECWRasterBand::GetBandIndexAndCountForStatistics(int &bandIndex, int &bandCount){
     403                 :     bandIndex = nBand-1;
     404                 :     bandCount = poGDS->nBands;
     405                 :     for (int i=0;i<poGDS->nBands;i++){
     406                 :         if (poDS->GetRasterBand(i+1)->GetColorInterpretation() == GCI_AlphaBand){
     407                 :             bandCount--;
     408                 :             if ( i < nBand-1 ){
     409                 :                 bandIndex--;
     410                 :             }
     411                 :         }
     412                 :         
     413                 :     }
     414                 : }
     415                 : 
     416                 : /************************************************************************/
     417                 : /*                          GetStatistics()                             */
     418                 : /************************************************************************/
     419                 : 
     420                 : CPLErr ECWRasterBand::GetStatistics( int bApproxOK, int bForce,
     421                 :                                   double *pdfMin, double *pdfMax, 
     422                 :                                   double *pdfMean, double *padfStdDev ){
     423                 :     int bForceCoalesced = bForce;
     424                 :     // If file version is smaller than 3, there will be no statistics in the file. But if it is version 3 or higher we don't want underlying implementation to compute histogram
     425                 :     // so we set bForceCoalesced to FALSE. 
     426                 :     if (poGDS->psFileInfo->nFormatVersion >= 3){
     427                 :         bForceCoalesced = FALSE;
     428                 :     }
     429                 :     // We check if we have PAM histogram. If we have them we return them. This will allow to override statistics stored in the file. 
     430                 :     CPLErr pamError =  GDALPamRasterBand::GetStatistics(bApproxOK, bForceCoalesced, pdfMin, pdfMax, pdfMean, padfStdDev);
     431                 :     if ( pamError == CE_None || poGDS->psFileInfo->nFormatVersion<3 ){
     432                 :         return pamError;
     433                 :     }
     434                 : 
     435                 :     NCS::CError error = poGDS->StatisticsEnsureInitialized();
     436                 :     if (!error.Success()){
     437                 :         CPLError( CE_Failure, CPLE_AppDefined,
     438                 :                         "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::GetStatistic. " );
     439                 :         return CE_Failure;
     440                 :     }
     441                 :     GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
     442                 :     if ( poGDS->pStatistics != NULL ){
     443                 :         
     444                 :         NCSBandStats& bandStats = poGDS->pStatistics->BandsStats[nStatsBandIndex];
     445                 :         if ( pdfMin != NULL ){
     446                 :             *pdfMin = bandStats.fMinVal;
     447                 :         }
     448                 :         if ( pdfMax != NULL ){
     449                 :             *pdfMax = bandStats.fMaxVal;
     450                 :         }
     451                 :         if ( pdfMean != NULL ){
     452                 :             *pdfMean = bandStats.fMeanVal;
     453                 :         }
     454                 :         if ( padfStdDev != NULL ){
     455                 :             *padfStdDev  = bandStats.fStandardDev;
     456                 :         }
     457                 :         return CE_None;
     458                 :     }else {
     459                 :         return CE_Warning;
     460                 :     }
     461                 :     
     462                 : }
     463                 : 
     464                 : /************************************************************************/
     465                 : /*                          SetStatistics()                             */
     466                 : /************************************************************************/
     467                 : 
     468                 : CPLErr ECWRasterBand::SetStatistics( double dfMin, double dfMax, 
     469                 :                                   double dfMean, double dfStdDev ){
     470                 :     if (poGDS->psFileInfo->nFormatVersion < 3){
     471                 :         return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
     472                 :     }
     473                 :     double dummy;
     474                 :     bool hasPAMStatistics = GDALPamRasterBand::GetStatistics(TRUE, FALSE, &dummy, &dummy, &dummy, &dummy) == CE_None;
     475                 :     
     476                 :     NCS::CError error = poGDS->StatisticsEnsureInitialized();
     477                 :     if (!error.Success()){
     478                 :             CPLError( CE_Warning, CPLE_AppDefined,
     479                 :                         "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::SetStatistic. Statistics will be written to PAM. " );
     480                 :             return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
     481                 :     }
     482                 :     GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
     483                 :     if (poGDS->pStatistics == NULL){
     484                 :         error = NCSEcwInitStatistics(&poGDS->pStatistics, nStatsBandCount, NULL);
     485                 :         if (!error.Success()){
     486                 :             CPLError( CE_Warning, CPLE_AppDefined,
     487                 :                         "NCSEcwInitStatistics failed in ECWRasterBand::SetStatistic. Statistics will be written to PAM." );
     488                 :             return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
     489                 :         }
     490                 :     }
     491                 :     
     492                 :     poGDS->pStatistics->BandsStats[nStatsBandIndex].fMinVal = (IEEE4) dfMin;
     493                 :     poGDS->pStatistics->BandsStats[nStatsBandIndex].fMaxVal = (IEEE4)dfMax;
     494                 :     poGDS->pStatistics->BandsStats[nStatsBandIndex].fMeanVal = (IEEE4)dfMean;
     495                 :     poGDS->pStatistics->BandsStats[nStatsBandIndex].fStandardDev = (IEEE4)dfStdDev;
     496                 :     poGDS->bStatisticsDirty = TRUE;
     497                 :     //if we have PAM statistics we need to save them as well. Better option would be to remove them from PAM file but I don't know how to do that without messing in PAM internals. 
     498                 :     if ( hasPAMStatistics ){
     499                 :         CPLError( CE_Debug, CPLE_AppDefined,
     500                 :                         "PAM statistics will be overwritten." );
     501                 :         return  GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
     502                 :     }
     503                 :     return CE_None;
     504                 :     
     505                 : }
     506                 : #endif
     507                 : 
     508                 : //#if !defined(SDK_CAN_DO_SUPERSAMPLING)
     509                 : /************************************************************************/
     510                 : /*                          OldIRasterIO()                              */
     511                 : /************************************************************************/
     512                 : 
     513                 : /* This implementation of IRasterIO(), derived from the one of GDAL 1.9 */
     514                 : /* and older versions, is meant at making over-sampling */
     515                 : /* work with ECW SDK 3.3. Newer versions of the SDK can do super-sampling in their */
     516                 : /* SetView() call. */
     517                 : 
     518               1 : CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
     519                 :                                  int nXOff, int nYOff, int nXSize, int nYSize,
     520                 :                                  void * pData, int nBufXSize, int nBufYSize,
     521                 :                                  GDALDataType eBufType,
     522                 :                                  int nPixelSpace, int nLineSpace )
     523                 :     
     524                 : {
     525                 :     int          iBand, bDirect;
     526               1 :     GByte        *pabyWorkBuffer = NULL;
     527               1 :     int nResFactor = 1 << (iOverview+1);
     528                 : 
     529               1 :     nXOff *= nResFactor;
     530               1 :     nYOff *= nResFactor;
     531               1 :     nXSize *= nResFactor;
     532               1 :     nYSize *= nResFactor;
     533                 : 
     534                 : /* -------------------------------------------------------------------- */
     535                 : /*      Try to do it based on existing "advised" access.                */
     536                 : /* -------------------------------------------------------------------- */
     537               1 :     if( poGDS->TryWinRasterIO( eRWFlag, 
     538                 :                                nXOff, nYOff, 
     539                 :                                nXSize, nYSize, 
     540                 :                                (GByte *) pData, nBufXSize, nBufYSize, 
     541                 :                                eBufType, 1, &nBand, 
     542                 :                                nPixelSpace, nLineSpace, 0 ) )
     543               0 :         return CE_None;
     544                 : 
     545                 : /* -------------------------------------------------------------------- */
     546                 : /*      The ECW SDK doesn't supersample, so adjust for this case.       */
     547                 : /* -------------------------------------------------------------------- */
     548                 : 
     549               1 :     int          nNewXSize = nBufXSize, nNewYSize = nBufYSize;
     550                 : 
     551               1 :     if ( nXSize < nBufXSize )
     552               1 :         nNewXSize = nXSize;
     553                 : 
     554               1 :     if ( nYSize < nBufYSize )
     555               1 :         nNewYSize = nYSize;
     556                 : 
     557                 : /* -------------------------------------------------------------------- */
     558                 : /*      Can we perform direct loads, or must we load into a working     */
     559                 : /*      buffer, and transform?                                          */
     560                 : /* -------------------------------------------------------------------- */
     561               1 :     int     nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
     562                 : 
     563                 :     bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
     564               1 :         && nNewXSize == nBufXSize && nNewYSize == nBufYSize;
     565               1 :     if( !bDirect )
     566               1 :         pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
     567                 : 
     568                 : /* -------------------------------------------------------------------- */
     569                 : /*      Establish access at the desired resolution.                     */
     570                 : /* -------------------------------------------------------------------- */
     571               1 :     CNCSError oErr;
     572                 : 
     573               1 :     poGDS->CleanupWindow();
     574                 : 
     575               1 :     iBand = nBand-1;
     576                 :     oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
     577                 :                                        nXOff, nYOff, 
     578                 :                                        nXOff + nXSize - 1, 
     579                 :                                        nYOff + nYSize - 1,
     580               1 :                                        nNewXSize, nNewYSize );
     581               1 :     if( oErr.GetErrorNumber() != NCS_SUCCESS )
     582                 :     {
     583               0 :         CPLFree( pabyWorkBuffer );
     584               0 :         ECWReportError(oErr);
     585                 : 
     586               0 :         return CE_Failure;
     587                 :     }
     588                 : 
     589                 : /* -------------------------------------------------------------------- */
     590                 : /*      Read back one scanline at a time, till request is satisfied.    */
     591                 : /*      Supersampling is not supported by the ECW API, so we will do    */
     592                 : /*      it ourselves.                                                   */
     593                 : /* -------------------------------------------------------------------- */
     594               1 :     double  dfSrcYInc = (double)nNewYSize / nBufYSize;
     595               1 :     double  dfSrcXInc = (double)nNewXSize / nBufXSize;
     596                 :     int         iSrcLine, iDstLine;
     597                 : 
     598             801 :     for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
     599                 :     {
     600                 :         NCSEcwReadStatus eRStatus;
     601             800 :         int         iDstLineOff = iDstLine * nLineSpace;
     602                 :         unsigned char   *pabySrcBuf;
     603                 : 
     604             800 :         if( bDirect )
     605               0 :             pabySrcBuf = ((GByte *)pData) + iDstLineOff;
     606                 :         else
     607             800 :             pabySrcBuf = pabyWorkBuffer;
     608                 : 
     609            1200 :         if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
     610                 :         {
     611                 :             eRStatus = poGDS->poFileView->ReadLineBIL( 
     612             400 :                 poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
     613                 : 
     614             400 :             if( eRStatus != NCSECW_READ_OK )
     615                 :             {
     616               0 :                 CPLFree( pabyWorkBuffer );
     617               0 :                 CPLDebug( "ECW", "ReadLineBIL status=%d", (int) eRStatus );
     618                 :                 CPLError( CE_Failure, CPLE_AppDefined,
     619               0 :                          "NCScbmReadViewLineBIL failed." );
     620               0 :                 return CE_Failure;
     621                 :             }
     622                 : 
     623             400 :             if( !bDirect )
     624                 :             {
     625             400 :                 if ( nNewXSize == nBufXSize )
     626                 :                 {
     627                 :                     GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType, 
     628                 :                                 nRawPixelSize, 
     629                 :                                 ((GByte *)pData) + iDstLine * nLineSpace, 
     630               0 :                                 eBufType, nPixelSpace, nBufXSize );
     631                 :                 }
     632                 :                 else
     633                 :                 {
     634                 :                     int iPixel;
     635                 : 
     636          320400 :                     for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
     637                 :                     {
     638                 :                         GDALCopyWords( pabyWorkBuffer 
     639                 :                                     + nRawPixelSize*((int)(iPixel*dfSrcXInc)),
     640                 :                                     poGDS->eRasterDataType, nRawPixelSize,
     641                 :                                     (GByte *)pData + iDstLineOff
     642                 :                                     + iPixel * nPixelSpace,
     643          320000 :                                                     eBufType, nPixelSpace, 1 );
     644                 :                     }
     645                 :                 }
     646                 :             }
     647                 : 
     648             400 :             iSrcLine++;
     649                 :         }
     650                 :         else
     651                 :         {
     652                 :             // Just copy the previous line in this case
     653                 :             GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
     654                 :                             eBufType, nPixelSpace,
     655                 :                             (GByte *)pData + iDstLineOff,
     656             400 :                             eBufType, nPixelSpace, nBufXSize );
     657                 :         }
     658                 :     }
     659                 : 
     660               1 :     CPLFree( pabyWorkBuffer );
     661                 : 
     662               1 :     return CE_None;
     663                 : }
     664                 : //#endif !defined(SDK_CAN_DO_SUPERSAMPLING)
     665                 : 
     666                 : /************************************************************************/
     667                 : /*                             IRasterIO()                              */
     668                 : /************************************************************************/
     669                 : 
     670           11774 : CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     671                 :                                  int nXOff, int nYOff, int nXSize, int nYSize,
     672                 :                                  void * pData, int nBufXSize, int nBufYSize,
     673                 :                                  GDALDataType eBufType,
     674                 :                                  int nPixelSpace, int nLineSpace )
     675                 : {
     676           11774 :     if( eRWFlag == GF_Write )
     677               0 :         return CE_Failure;
     678                 : 
     679                 :     /* -------------------------------------------------------------------- */
     680                 :     /*      Default line and pixel spacing if needed.                       */
     681                 :     /* -------------------------------------------------------------------- */
     682           11774 :     if ( nPixelSpace == 0 )
     683               0 :         nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
     684                 : 
     685           11774 :     if ( nLineSpace == 0 )
     686               0 :         nLineSpace = nPixelSpace * nBufXSize;
     687                 : 
     688                 :     CPLDebug( "ECWRasterBand", 
     689                 :             "RasterIO(nBand=%d,iOverview=%d,nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)", 
     690           11774 :             nBand, iOverview, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
     691                 : 
     692                 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
     693           11774 :     if( poGDS->bUseOldBandRasterIOImplementation )
     694                 :     {
     695                 :         return OldIRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     696                 :                             pData, nBufXSize, nBufYSize,
     697                 :                             eBufType,
     698               1 :                             nPixelSpace, nLineSpace );
     699                 :     }
     700                 : 
     701                 : #endif
     702                 : 
     703           11773 :     int nResFactor = 1 << (iOverview+1);
     704                 : 
     705                 :     return poGDS->IRasterIO(eRWFlag,
     706                 :                             nXOff * nResFactor,
     707                 :                             nYOff * nResFactor,
     708                 :                             (nXSize == nRasterXSize) ? poGDS->nRasterXSize : nXSize * nResFactor,
     709                 :                             (nYSize == nRasterYSize) ? poGDS->nRasterYSize : nYSize * nResFactor,
     710                 :                             pData, nBufXSize, nBufYSize,
     711                 :                             eBufType, 1, &nBand,
     712           11773 :                             nPixelSpace, nLineSpace, nLineSpace*nBufYSize);
     713                 : }
     714                 : 
     715                 : /************************************************************************/
     716                 : /*                             IReadBlock()                             */
     717                 : /************************************************************************/
     718                 : 
     719               1 : CPLErr ECWRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
     720                 : 
     721                 : {
     722               1 :     int nXOff = nBlockXOff * nBlockXSize,
     723               1 :         nYOff = nBlockYOff * nBlockYSize,
     724               1 :         nXSize = nBlockXSize,
     725               1 :         nYSize = nBlockYSize;
     726                 : 
     727               1 :     if( nXOff + nXSize > nRasterXSize )
     728               0 :         nXSize = nRasterXSize - nXOff;
     729               1 :     if( nYOff + nYSize > nRasterYSize )
     730               0 :         nYSize = nRasterYSize - nYOff;
     731                 : 
     732               1 :     int nPixelSpace = GDALGetDataTypeSize(eDataType) / 8;
     733               1 :     int nLineSpace = nPixelSpace * nBlockXSize;
     734                 :     return IRasterIO( GF_Read,
     735                 :                       nXOff, nYOff, nXSize, nYSize,
     736                 :                       pImage, nXSize, nYSize,
     737               1 :                       eDataType, nPixelSpace, nLineSpace );
     738                 : }
     739                 : 
     740                 : /************************************************************************/
     741                 : /* ==================================================================== */
     742                 : /*                            ECWDataset                               */
     743                 : /* ==================================================================== */
     744                 : /************************************************************************/
     745                 : 
     746                 : 
     747                 : /************************************************************************/
     748                 : /*                            ECWDataset()                              */
     749                 : /************************************************************************/
     750                 : 
     751              68 : ECWDataset::ECWDataset(int bIsJPEG2000)
     752                 : 
     753                 : {
     754              68 :     this->bIsJPEG2000 = bIsJPEG2000;
     755              68 :     bUsingCustomStream = FALSE;
     756              68 :     pszProjection = NULL;
     757              68 :     poFileView = NULL;
     758              68 :     bWinActive = FALSE;
     759              68 :     panWinBandList = NULL;
     760              68 :     eRasterDataType = GDT_Byte;
     761              68 :     nGCPCount = 0;
     762              68 :     pasGCPList = NULL;
     763              68 :     papszGMLMetadata = NULL;
     764                 :     
     765              68 :     bGeoTransformValid = FALSE;
     766              68 :     adfGeoTransform[0] = 0.0;
     767              68 :     adfGeoTransform[1] = 1.0;
     768              68 :     adfGeoTransform[2] = 0.0;
     769              68 :     adfGeoTransform[3] = 0.0;
     770              68 :     adfGeoTransform[4] = 0.0;
     771              68 :     adfGeoTransform[5] = 1.0;
     772                 : 
     773              68 :     bHdrDirty = FALSE;
     774              68 :     bGeoTransformChanged = FALSE;
     775              68 :     bProjectionChanged = FALSE;
     776              68 :     bProjCodeChanged = FALSE;
     777              68 :     bDatumCodeChanged = FALSE;
     778              68 :     bUnitsCodeChanged = FALSE;
     779                 :     
     780              68 :     bUseOldBandRasterIOImplementation = FALSE;
     781                 : #if ECWSDK_VERSION>=50
     782                 : 
     783                 :     pStatistics = NULL;
     784                 :     bStatisticsDirty = FALSE;
     785                 :     bStatisticsInitialized = FALSE;
     786                 : 
     787                 : #endif 
     788                 :     
     789              68 :     sCachedMultiBandIO.bEnabled = FALSE;
     790              68 :     sCachedMultiBandIO.nBandsTried = 0;
     791              68 :     sCachedMultiBandIO.nXOff = 0;
     792              68 :     sCachedMultiBandIO.nYOff = 0;
     793              68 :     sCachedMultiBandIO.nXSize = 0;
     794              68 :     sCachedMultiBandIO.nYSize = 0;
     795              68 :     sCachedMultiBandIO.nBufXSize = 0;
     796              68 :     sCachedMultiBandIO.nBufYSize = 0;
     797              68 :     sCachedMultiBandIO.eBufType = GDT_Unknown;
     798              68 :     sCachedMultiBandIO.pabyData = NULL;
     799                 :     
     800              68 :     poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
     801              68 : }
     802                 : 
     803                 : /************************************************************************/
     804                 : /*                           ~ECWDataset()                              */
     805                 : /************************************************************************/
     806                 : 
     807              68 : ECWDataset::~ECWDataset()
     808                 : 
     809                 : {
     810              68 :     FlushCache();
     811              68 :     CleanupWindow();
     812                 : 
     813                 : /* -------------------------------------------------------------------- */
     814                 : /*      Release / dereference iostream.                                 */
     815                 : /* -------------------------------------------------------------------- */
     816                 :     // The underlying iostream of the CNCSJP2FileView (poFileView) object may 
     817                 :     // also be the underlying iostream of other CNCSJP2FileView (poFileView) 
     818                 :     // objects.  Consequently, when we delete the CNCSJP2FileView (poFileView) 
     819                 :     // object, we must decrement the nFileViewCount attribute of the underlying
     820                 :     // VSIIOStream object, and only delete the VSIIOStream object when 
     821                 :     // nFileViewCount is equal to zero.
     822                 : 
     823              68 :     CPLMutexHolder oHolder( &hECWDatasetMutex );
     824                 : 
     825                 :     // GDAL_CLOSE_JP2ECW_RESOURCE is set to NO by gdaldllmain.cpp/GDALDestroy() so as
     826                 :     // to avoid an issue with the ECW SDK 3.3 where the destructor of CNCSJP2File::CNCSJP2FileVector CNCSJP2File::sm_Files;
     827                 :     // static ressource allocated in NCJP2File.cpp can be called before GDALDestroy(), causing
     828                 :     // ECW SDK resources ( CNCSJP2File files ) to be closed before we get here.
     829              68 :     if( poFileView != NULL &&
     830                 :         (!bIsJPEG2000 || CSLTestBoolean(CPLGetConfigOption("GDAL_CLOSE_JP2ECW_RESOURCE", "YES"))) )
     831                 :     {
     832              68 :         VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
     833                 : 
     834              68 :         poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
     835              68 :         delete poFileView;
     836                 : 
     837              68 :         if( bUsingCustomStream )
     838                 :         {
     839              15 :             if( --poUnderlyingIOStream->nFileViewCount == 0 )
     840              15 :                 delete poUnderlyingIOStream;
     841                 :         }
     842                 :     }
     843                 : 
     844                 :     /* WriteHeader() must be called after closing the file handle to work */
     845                 :     /* on Windows */
     846              68 :     if( bHdrDirty )
     847               3 :         WriteHeader();
     848                 :     #if ECWSDK_VERSION>=50
     849                 : 
     850                 :     if (bStatisticsDirty){
     851                 :         StatisticsWrite();
     852                 :     }
     853                 :     CleanupStatistics();
     854                 :     
     855                 :     #endif 
     856                 : 
     857              68 :     CPLFree( pszProjection );
     858              68 :     CSLDestroy( papszGMLMetadata );
     859                 : 
     860              68 :     if( nGCPCount > 0 )
     861                 :     {
     862               4 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     863               4 :         CPLFree( pasGCPList );
     864                 :     }
     865                 : 
     866              68 :     CPLFree(sCachedMultiBandIO.pabyData);
     867              68 : }
     868                 : 
     869                 : #if ECWSDK_VERSION>=50
     870                 : 
     871                 : /************************************************************************/
     872                 : /*                    StatisticsEnsureInitialized()                     */
     873                 : /************************************************************************/
     874                 : 
     875                 : NCS::CError ECWDataset::StatisticsEnsureInitialized(){
     876                 :     if (bStatisticsInitialized == TRUE){
     877                 :         return NCS_SUCCESS;
     878                 :     }
     879                 :     
     880                 :     NCS::CError error = poFileView->GetClientStatistics(&pStatistics);
     881                 :     if (error.Success()){
     882                 :         bStatisticsInitialized = TRUE;
     883                 :     }
     884                 :     return error;
     885                 : }
     886                 : 
     887                 : /************************************************************************/
     888                 : /*                          StatisticsWrite()                           */
     889                 : /************************************************************************/
     890                 : 
     891                 : NCS::CError ECWDataset::StatisticsWrite(){
     892                 :     
     893                 :     NCSFileView* view = NCSEcwEditOpen( GetDescription() );
     894                 :     NCS::CError error;
     895                 :     if ( view != NULL ){
     896                 :         error = NCSEcwEditSetStatistics(view, pStatistics);
     897                 :         if (error.Success()){
     898                 :             error = NCSEcwEditFlushAll(view);
     899                 :             if (error.Success()){
     900                 :                 error = NCSEcwEditClose(view);
     901                 :             }
     902                 :         }
     903                 :     } 
     904                 :     
     905                 :     bStatisticsDirty = FALSE;
     906                 :     
     907                 :     return error;
     908                 :     
     909                 : }
     910                 : 
     911                 : /************************************************************************/
     912                 : /*                          CleanupStatistics()                         */
     913                 : /************************************************************************/
     914                 : 
     915                 : void ECWDataset::CleanupStatistics(){
     916                 :     if (bStatisticsInitialized == TRUE && pStatistics !=NULL){
     917                 :         NCSEcwFreeStatistics(pStatistics);
     918                 :     }
     919                 : }
     920                 : 
     921                 : #endif // #if ECWSDK_VERSION>=50
     922                 : 
     923                 : /************************************************************************/
     924                 : /*                          SetGeoTransform()                           */
     925                 : /************************************************************************/
     926                 : 
     927               6 : CPLErr ECWDataset::SetGeoTransform( double * padfGeoTransform )
     928                 : {
     929               6 :     if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
     930               5 :         return GDALPamDataset::SetGeoTransform(padfGeoTransform);
     931                 : 
     932               2 :     if ( !bGeoTransformValid ||
     933               1 :         adfGeoTransform[0] != padfGeoTransform[0] ||
     934               0 :         adfGeoTransform[1] != padfGeoTransform[1] ||
     935               0 :         adfGeoTransform[2] != padfGeoTransform[2] ||
     936               0 :         adfGeoTransform[3] != padfGeoTransform[3] ||
     937               0 :         adfGeoTransform[4] != padfGeoTransform[4] ||
     938               0 :         adfGeoTransform[5] != padfGeoTransform[5] )
     939                 :     {
     940               1 :         memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
     941               1 :         bGeoTransformValid = TRUE;
     942               1 :         bHdrDirty = TRUE;
     943               1 :         bGeoTransformChanged = TRUE;
     944                 :     }
     945                 : 
     946               1 :     return CE_None;
     947                 : }
     948                 : 
     949                 : /************************************************************************/
     950                 : /*                            SetProjection()                           */
     951                 : /************************************************************************/
     952                 : 
     953               6 : CPLErr ECWDataset::SetProjection( const char* pszProjectionIn )
     954                 : {
     955               6 :     if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
     956               5 :         return GDALPamDataset::SetProjection(pszProjectionIn);
     957                 : 
     958               1 :     if ( !( (pszProjection == NULL && pszProjectionIn == NULL) ||
     959                 :             (pszProjection != NULL && pszProjectionIn != NULL &&
     960                 :              strcmp(pszProjection, pszProjectionIn) == 0) ) )
     961                 :     {
     962               1 :         CPLFree(pszProjection);
     963               1 :         pszProjection = pszProjectionIn ? CPLStrdup(pszProjectionIn) : NULL;
     964               1 :         bHdrDirty = TRUE;
     965               1 :         bProjectionChanged = TRUE;
     966                 :     }
     967                 : 
     968               1 :     return CE_None;
     969                 : }
     970                 : 
     971                 : /************************************************************************/
     972                 : /*                            SetMetadataItem()                         */
     973                 : /************************************************************************/
     974                 : 
     975               3 : CPLErr ECWDataset::SetMetadataItem( const char * pszName,
     976                 :                                     const char * pszValue,
     977                 :                                     const char * pszDomain )
     978                 : {
     979               3 :     if ( !bIsJPEG2000 && eAccess == GA_Update &&
     980                 :          (pszDomain == NULL || EQUAL(pszDomain, "") ||
     981                 :           (pszDomain != NULL && EQUAL(pszDomain, "ECW"))) &&
     982                 :          pszName != NULL &&
     983                 :          (strcmp(pszName, "PROJ") == 0 || strcmp( pszName, "DATUM") == 0 ||
     984                 :           strcmp( pszName, "UNITS") == 0 ) )
     985                 :     {
     986               3 :         CPLString osNewVal = pszValue ? pszValue : "";
     987               3 :         if (osNewVal.size() > 31)
     988               0 :             osNewVal.resize(31);
     989               3 :         if (strcmp(pszName, "PROJ") == 0)
     990                 :         {
     991               1 :             bProjCodeChanged = (osNewVal != m_osProjCode);
     992               1 :             m_osProjCode = osNewVal;
     993               1 :             bHdrDirty |= bProjCodeChanged;
     994                 :         }
     995               2 :         else if (strcmp( pszName, "DATUM") == 0)
     996                 :         {
     997               1 :             bDatumCodeChanged |= (osNewVal != m_osDatumCode)? TRUE:FALSE ;
     998               1 :             m_osDatumCode = osNewVal;
     999               1 :             bHdrDirty |= bDatumCodeChanged;
    1000                 :         }
    1001                 :         else 
    1002                 :         {
    1003               1 :             bUnitsCodeChanged |= (osNewVal != m_osUnitsCode)?TRUE:FALSE;
    1004               1 :             m_osUnitsCode = osNewVal;
    1005               1 :             bHdrDirty |= bUnitsCodeChanged;
    1006                 :         }
    1007               3 :         return CE_None;
    1008                 :     }
    1009                 :     else
    1010               0 :         return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
    1011                 : }
    1012                 : 
    1013                 : /************************************************************************/
    1014                 : /*                              SetMetadata()                           */
    1015                 : /************************************************************************/
    1016                 : 
    1017              15 : CPLErr ECWDataset::SetMetadata( char ** papszMetadata,
    1018                 :                                 const char * pszDomain )
    1019                 : {
    1020              15 :     if ( (pszDomain == NULL || EQUAL(pszDomain, "") || EQUAL(pszDomain, "ECW")) &&
    1021                 :           (CSLFetchNameValue(papszMetadata, "PROJ") != NULL ||
    1022                 :            CSLFetchNameValue(papszMetadata, "DATUM") != NULL ||
    1023                 :            CSLFetchNameValue(papszMetadata, "UNITS") != NULL) )
    1024                 :     {
    1025               0 :         CPLStringList osNewMetadata;
    1026               0 :         char** papszIter = papszMetadata;
    1027               0 :         while(*papszIter)
    1028                 :         {
    1029               0 :             if (strncmp(*papszIter, "PROJ=", 5) == 0 ||
    1030                 :                 strncmp(*papszIter, "DATUM=", 6) == 0 ||
    1031                 :                 strncmp(*papszIter, "UNITS=", 6) == 0)
    1032                 :             {
    1033               0 :                 char* pszKey = NULL;
    1034               0 :                 const char* pszValue = CPLParseNameValue(*papszIter, &pszKey );
    1035               0 :                 SetMetadataItem(pszKey, pszValue, pszDomain);
    1036               0 :                 CPLFree(pszKey);
    1037                 :             }
    1038                 :             else
    1039               0 :                 osNewMetadata.AddString(*papszIter);
    1040               0 :             papszIter ++;
    1041                 :         }
    1042               0 :         if (osNewMetadata.size() != 0)
    1043               0 :             return GDALPamDataset::SetMetadata(osNewMetadata.List(), pszDomain);
    1044                 :         else
    1045               0 :             return CE_None;
    1046                 :     }
    1047                 :     else
    1048              15 :         return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
    1049                 : }
    1050                 : 
    1051                 : /************************************************************************/
    1052                 : /*                             WriteHeader()                            */
    1053                 : /************************************************************************/
    1054                 : 
    1055               3 : void ECWDataset::WriteHeader()
    1056                 : {
    1057               3 :     if (!bHdrDirty)
    1058               0 :         return;
    1059                 : 
    1060               3 :     CPLAssert(eAccess == GA_Update);
    1061               3 :     CPLAssert(!bIsJPEG2000);
    1062                 : 
    1063               3 :     bHdrDirty = FALSE;
    1064                 : 
    1065               3 :     NCSEcwEditInfo *psEditInfo = NULL;
    1066                 :     NCSError eErr;
    1067                 : 
    1068                 :     /* Load original header info */
    1069                 : #if ECWSDK_VERSION<50
    1070               3 :     eErr = NCSEcwEditReadInfo((char*) GetDescription(), &psEditInfo);
    1071                 : #else 
    1072                 :     eErr = NCSEcwEditReadInfo(  NCS::CString::Utf8Decode(GetDescription()).c_str(), &psEditInfo);
    1073                 : #endif
    1074               3 :     if (eErr != NCS_SUCCESS)
    1075                 :     {
    1076               0 :         CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditReadInfo() failed");
    1077               0 :         return;
    1078                 :     }
    1079                 : 
    1080                 :     /* To avoid potential cross-heap issues, we keep the original */
    1081                 :     /* strings, and restore them before freeing the structure */
    1082               3 :     char* pszOriginalCode = psEditInfo->szDatum;
    1083               3 :     char* pszOriginalProj = psEditInfo->szProjection;
    1084                 : 
    1085                 :     /* Alter the structure with user modified information */
    1086                 :     char szProjCode[32], szDatumCode[32], szUnits[32];
    1087               3 :     if (bProjectionChanged)
    1088                 :     {
    1089               1 :         if (ECWTranslateFromWKT( pszProjection, szProjCode, sizeof(szProjCode),
    1090                 :                                  szDatumCode, sizeof(szDatumCode), szUnits ) )
    1091                 :         {
    1092               1 :             psEditInfo->szDatum = szDatumCode;
    1093               1 :             psEditInfo->szProjection = szProjCode;
    1094               1 :             psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
    1095               1 :             CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
    1096               1 :             CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
    1097                 :             CPLDebug("ECW", "Rewrite UNITS : %s",
    1098               1 :                      ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
    1099                 :         }
    1100                 :     }
    1101                 : 
    1102               3 :     if (bDatumCodeChanged)
    1103                 :     {
    1104               1 :         psEditInfo->szDatum = (char*) ((m_osDatumCode.size()) ? m_osDatumCode.c_str() : "RAW");
    1105               1 :         CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
    1106                 :     }
    1107               3 :     if (bProjCodeChanged)
    1108                 :     {
    1109               1 :         psEditInfo->szProjection = (char*) ((m_osProjCode.size()) ? m_osProjCode.c_str() : "RAW");
    1110               1 :         CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
    1111                 :     }
    1112               3 :     if (bUnitsCodeChanged)
    1113                 :     {
    1114               1 :         psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(m_osUnitsCode.c_str());
    1115                 :         CPLDebug("ECW", "Rewrite UNITS : %s",
    1116               1 :                  ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
    1117                 :     }
    1118                 : 
    1119               3 :     if (bGeoTransformChanged)
    1120                 :     {
    1121               1 :         psEditInfo->fOriginX = adfGeoTransform[0];
    1122               1 :         psEditInfo->fCellIncrementX = adfGeoTransform[1];
    1123               1 :         psEditInfo->fOriginY = adfGeoTransform[3];
    1124               1 :         psEditInfo->fCellIncrementY = adfGeoTransform[5];
    1125               1 :         CPLDebug("ECW", "Rewrite Geotransform");
    1126                 :     }
    1127                 : 
    1128                 :     /* Write modified header info */
    1129                 : #if ECWSDK_VERSION<50
    1130               3 :     eErr = NCSEcwEditWriteInfo((char*) GetDescription(), psEditInfo, NULL, NULL, NULL);
    1131                 : #else
    1132                 :     eErr = NCSEcwEditWriteInfo( NCS::CString::Utf8Decode(GetDescription()).c_str(), psEditInfo, NULL, NULL, NULL);
    1133                 : #endif
    1134               3 :     if (eErr != NCS_SUCCESS)
    1135                 :     {
    1136               0 :         CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditWriteInfo() failed");
    1137                 :     }
    1138                 : 
    1139                 :     /* Restore original pointers before free'ing */
    1140               3 :     psEditInfo->szDatum = pszOriginalCode;
    1141               3 :     psEditInfo->szProjection = pszOriginalProj;
    1142                 : 
    1143               3 :     NCSEcwEditFreeInfo(psEditInfo);
    1144                 : }
    1145                 : 
    1146                 : /************************************************************************/
    1147                 : /*                             AdviseRead()                             */
    1148                 : /************************************************************************/
    1149                 : 
    1150              29 : CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
    1151                 :                                int nBufXSize, int nBufYSize, 
    1152                 :                                GDALDataType eDT, 
    1153                 :                                int nBandCount, int *panBandList,
    1154                 :                                char **papszOptions )
    1155                 : 
    1156                 : {
    1157              29 :     int *panAdjustedBandList = NULL;
    1158                 : 
    1159                 :     CPLDebug( "ECW",
    1160                 :               "ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
    1161              29 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
    1162                 : 
    1163                 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
    1164              29 :     if( nBufXSize > nXSize || nBufYSize > nYSize )
    1165                 :     {
    1166                 :         CPLError( CE_Warning, CPLE_AppDefined, 
    1167                 :                   "Supersampling not directly supported by ECW toolkit,\n"
    1168               0 :                   "ignoring AdviseRead() request." );
    1169               0 :         return CE_Warning; 
    1170                 :     }
    1171                 : #endif
    1172                 : 
    1173                 : /* -------------------------------------------------------------------- */
    1174                 : /*      Adjust band numbers to be zero based.                           */
    1175                 : /* -------------------------------------------------------------------- */
    1176                 :     panAdjustedBandList = (int *) 
    1177              29 :         CPLMalloc(sizeof(int) * nBandCount );
    1178              60 :     for( int ii= 0; ii < nBandCount; ii++ )
    1179              31 :         panAdjustedBandList[ii] = panBandList[ii] - 1;
    1180                 : 
    1181                 : /* -------------------------------------------------------------------- */
    1182                 : /*      Cleanup old window cache information.                           */
    1183                 : /* -------------------------------------------------------------------- */
    1184              29 :     CleanupWindow();
    1185                 : 
    1186                 : /* -------------------------------------------------------------------- */
    1187                 : /*      Set the new requested window.                                   */
    1188                 : /* -------------------------------------------------------------------- */
    1189              29 :     CNCSError oErr;
    1190                 :     
    1191                 :     oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList, 
    1192                 :                                 nXOff, nYOff, 
    1193                 :                                 nXOff + nXSize-1, nYOff + nYSize-1,
    1194              29 :                                 nBufXSize, nBufYSize );
    1195                 : 
    1196              29 :     CPLFree( panAdjustedBandList );
    1197              29 :     if( oErr.GetErrorNumber() != NCS_SUCCESS )
    1198                 :     {
    1199               0 :         ECWReportError(oErr);
    1200                 : 
    1201               0 :         bWinActive = FALSE;
    1202               0 :         return CE_Failure;
    1203                 :     }
    1204                 : 
    1205              29 :     bWinActive = TRUE;
    1206                 : 
    1207                 : /* -------------------------------------------------------------------- */
    1208                 : /*      Record selected window.                                         */
    1209                 : /* -------------------------------------------------------------------- */
    1210              29 :     nWinXOff = nXOff;
    1211              29 :     nWinYOff = nYOff;
    1212              29 :     nWinXSize = nXSize;
    1213              29 :     nWinYSize = nYSize;
    1214              29 :     nWinBufXSize = nBufXSize;
    1215              29 :     nWinBufYSize = nBufYSize;
    1216                 : 
    1217              29 :     panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
    1218              29 :     memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
    1219              29 :     nWinBandCount = nBandCount;
    1220                 : 
    1221              29 :     nWinBufLoaded = -1;
    1222                 : 
    1223                 : /* -------------------------------------------------------------------- */
    1224                 : /*      Allocate current scanline buffer.                               */
    1225                 : /* -------------------------------------------------------------------- */
    1226              29 :     papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
    1227              60 :     for( int iBand = 0; iBand < nWinBandCount; iBand++ )
    1228              31 :         papCurLineBuf[iBand] = 
    1229              31 :             CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
    1230                 :         
    1231              29 :     return CE_None;
    1232                 : }
    1233                 : 
    1234                 : /************************************************************************/
    1235                 : /*                           TryWinRasterIO()                           */
    1236                 : /*                                                                      */
    1237                 : /*      Try to satisfy the given request based on the currently         */
    1238                 : /*      defined window.  Return TRUE on success or FALSE on             */
    1239                 : /*      failure.  On failure, the caller should satisfy the request     */
    1240                 : /*      another way (not report an error).                              */
    1241                 : /************************************************************************/
    1242                 : 
    1243           12204 : int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag, 
    1244                 :                                 int nXOff, int nYOff, int nXSize, int nYSize,
    1245                 :                                 GByte *pabyData, int nBufXSize, int nBufYSize, 
    1246                 :                                 GDALDataType eDT,
    1247                 :                                 int nBandCount, int *panBandList, 
    1248                 :                                 int nPixelSpace, int nLineSpace, 
    1249                 :                                 int nBandSpace )
    1250                 : 
    1251                 : {
    1252                 :     int iBand, i;
    1253                 : 
    1254                 : /* -------------------------------------------------------------------- */
    1255                 : /*      Provide default buffer organization.                            */
    1256                 : /* -------------------------------------------------------------------- */
    1257           12204 :     if( nPixelSpace == 0 )
    1258               0 :         nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
    1259           12204 :     if( nLineSpace == 0 )
    1260               0 :         nLineSpace = nPixelSpace * nBufXSize;
    1261           12204 :     if( nBandSpace == 0 )
    1262               1 :         nBandSpace = nLineSpace * nBufYSize;
    1263                 : 
    1264                 : /* -------------------------------------------------------------------- */
    1265                 : /*      Do some simple tests to see if the current window can           */
    1266                 : /*      satisfy our requirement.                                        */
    1267                 : /* -------------------------------------------------------------------- */
    1268                 : #ifdef NOISY_DEBUG
    1269                 :     CPLDebug( "ECW", "TryWinRasterIO(%d,%d,%d,%d,%d,%d)", 
    1270                 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
    1271                 : #endif
    1272                 : 
    1273           12204 :     if( !bWinActive )
    1274              54 :         return FALSE;
    1275                 :     
    1276           12150 :     if( nXOff != nWinXOff || nXSize != nWinXSize )
    1277               0 :         return FALSE;
    1278                 : 
    1279           12150 :     if( nBufXSize != nWinBufXSize )
    1280               0 :         return FALSE;
    1281                 : 
    1282           25092 :     for( iBand = 0; iBand < nBandCount; iBand++ )
    1283                 :     {
    1284           14158 :         for( i = 0; i < nWinBandCount; i++ )
    1285                 :         {
    1286           14150 :             if( panWinBandList[i] == panBandList[iBand] )
    1287           12942 :                 break;
    1288                 :         }
    1289                 : 
    1290           12950 :         if( i == nWinBandCount )
    1291               8 :             return FALSE;
    1292                 :     }
    1293                 : 
    1294           12142 :     if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
    1295               0 :         return FALSE;
    1296                 : 
    1297                 : /* -------------------------------------------------------------------- */
    1298                 : /*      Now we try more subtle tests.                                   */
    1299                 : /* -------------------------------------------------------------------- */
    1300                 :     {
    1301                 :         static int nDebugCount = 0;
    1302                 : 
    1303           12142 :         if( nDebugCount < 30 )
    1304                 :             CPLDebug( "ECW", 
    1305                 :                       "TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.", 
    1306              30 :                       nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
    1307                 : 
    1308           12142 :         if( nDebugCount == 29 )
    1309               1 :             CPLDebug( "ECW", "No more TryWinRasterIO messages will be reported" );
    1310                 :         
    1311           12142 :         nDebugCount++;
    1312                 :     }
    1313                 : 
    1314                 : /* -------------------------------------------------------------------- */
    1315                 : /*      Actually load data one buffer line at a time.                   */
    1316                 : /* -------------------------------------------------------------------- */
    1317                 :     int iBufLine;
    1318                 : 
    1319           24284 :     for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
    1320                 :     {
    1321           12142 :         double fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
    1322                 :         int iWinLine = 
    1323           12142 :             (int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
    1324                 :         
    1325           12142 :         if( iWinLine == nWinBufLoaded + 1 )
    1326           12142 :             LoadNextLine();
    1327                 : 
    1328           12142 :         if( iWinLine != nWinBufLoaded )
    1329               0 :             return FALSE;
    1330                 : 
    1331                 : /* -------------------------------------------------------------------- */
    1332                 : /*      Copy out all our target bands.                                  */
    1333                 : /* -------------------------------------------------------------------- */
    1334                 :         int iWinBand;
    1335           25084 :         for( iBand = 0; iBand < nBandCount; iBand++ )
    1336                 :         {
    1337           14142 :             for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
    1338                 :             {
    1339           14142 :                 if( panWinBandList[iWinBand] == panBandList[iBand] )
    1340           12942 :                     break;
    1341                 :             }
    1342                 : 
    1343                 :             GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
    1344                 :                            GDALGetDataTypeSize( eRasterDataType ) / 8, 
    1345                 :                            pabyData + nBandSpace * iBand 
    1346                 :                            + iBufLine * nLineSpace, eDT, nPixelSpace,
    1347           12942 :                            nBufXSize );
    1348                 :         }
    1349                 :     }
    1350                 : 
    1351           12142 :     return TRUE;
    1352                 : }
    1353                 : 
    1354                 : /************************************************************************/
    1355                 : /*                            LoadNextLine()                            */
    1356                 : /************************************************************************/
    1357                 : 
    1358           12142 : CPLErr ECWDataset::LoadNextLine()
    1359                 : 
    1360                 : {
    1361           12142 :     if( !bWinActive )
    1362               0 :         return CE_Failure;
    1363                 : 
    1364           12142 :     if( nWinBufLoaded == nWinBufYSize-1 )
    1365                 :     {
    1366               0 :         CleanupWindow();
    1367               0 :         return CE_Failure;
    1368                 :     }
    1369                 : 
    1370                 :     NCSEcwReadStatus  eRStatus;
    1371                 :     eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, 
    1372                 :                                         (UINT16) nWinBandCount,
    1373           12142 :                                         papCurLineBuf );
    1374           12142 :     if( eRStatus != NCSECW_READ_OK )
    1375               0 :         return CE_Failure;
    1376                 : 
    1377           12142 :     nWinBufLoaded++;
    1378                 : 
    1379           12142 :     return CE_None;
    1380                 : }
    1381                 : 
    1382                 : /************************************************************************/
    1383                 : /*                           CleanupWindow()                            */
    1384                 : /************************************************************************/
    1385                 : 
    1386             129 : void ECWDataset::CleanupWindow()
    1387                 : 
    1388                 : {
    1389             129 :     if( !bWinActive )
    1390             100 :         return;
    1391                 : 
    1392              29 :     bWinActive = FALSE;
    1393              29 :     CPLFree( panWinBandList );
    1394              29 :     panWinBandList = NULL;
    1395                 : 
    1396              60 :     for( int iBand = 0; iBand < nWinBandCount; iBand++ )
    1397              31 :         CPLFree( papCurLineBuf[iBand] );
    1398              29 :     CPLFree( papCurLineBuf );
    1399              29 :     papCurLineBuf = NULL;
    1400                 : }
    1401                 : 
    1402                 : /************************************************************************/
    1403                 : /*                             IRasterIO()                              */
    1404                 : /************************************************************************/
    1405                 : 
    1406           12180 : CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
    1407                 :                               int nXOff, int nYOff, int nXSize, int nYSize,
    1408                 :                               void * pData, int nBufXSize, int nBufYSize,
    1409                 :                               GDALDataType eBufType, 
    1410                 :                               int nBandCount, int *panBandMap,
    1411                 :                               int nPixelSpace, int nLineSpace, int nBandSpace)
    1412                 :     
    1413                 : {
    1414           12180 :     if( eRWFlag == GF_Write )
    1415               0 :         return CE_Failure;
    1416                 : 
    1417           12180 :     if( nBandCount > 100 )
    1418               0 :         return CE_Failure;
    1419                 : 
    1420           12180 :     if( bUseOldBandRasterIOImplementation )
    1421                 :         /* Sanity check. Shouldn't happen */
    1422               0 :         return CE_Failure;
    1423           12180 :     int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
    1424                 : 
    1425           12180 :     if ( nPixelSpace == 0 ){
    1426               0 :         nPixelSpace = nDataTypeSize;
    1427                 :     }
    1428                 :      
    1429           12180 :     if (nLineSpace == 0 ) {
    1430               0 :         nLineSpace = nPixelSpace*nBufXSize;
    1431                 :     }
    1432           12180 :     if ( nBandSpace == 0 ){
    1433               0 :         nBandSpace = nDataTypeSize*nBufXSize*nBufYSize;
    1434                 :     }
    1435                 : /* -------------------------------------------------------------------- */
    1436                 : /*      ECW SDK 3.3 has a bug with the ECW format when we query the     */
    1437                 : /*      number of bands of the dataset, but not in the "natural order". */
    1438                 : /*      It ignores the content of panBandMap. (#4234)                   */
    1439                 : /* -------------------------------------------------------------------- */
    1440                 : #if ECWSDK_VERSION < 40
    1441           12180 :     if( !bIsJPEG2000 && nBandCount == nBands )
    1442                 :     {
    1443                 :         int i;
    1444             406 :         int bDoBandIRasterIO = FALSE;
    1445            1624 :         for( i = 0; i < nBandCount; i++ )
    1446                 :         {
    1447            1218 :             if( panBandMap[i] != i + 1 )
    1448                 :             {
    1449               2 :                 bDoBandIRasterIO = TRUE;
    1450                 :             }
    1451                 :         }
    1452             406 :         if( bDoBandIRasterIO )
    1453                 :         {
    1454                 :             return GDALDataset::IRasterIO(
    1455                 :                                     eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1456                 :                                     pData, nBufXSize, nBufYSize,
    1457                 :                                     eBufType, 
    1458                 :                                     nBandCount, panBandMap,
    1459               1 :                                     nPixelSpace, nLineSpace, nBandSpace);
    1460                 :         }
    1461                 :     }
    1462                 : #endif
    1463                 : 
    1464                 : /* -------------------------------------------------------------------- */
    1465                 : /*      Check if we can directly return the data in case we have cached */
    1466                 : /*      it from a previous call in a multi-band reading pattern.        */
    1467                 : /* -------------------------------------------------------------------- */
    1468           12179 :     if( nBandCount == 1 && *panBandMap > 1 && *panBandMap <= nBands &&
    1469                 :         sCachedMultiBandIO.nXOff == nXOff &&
    1470                 :         sCachedMultiBandIO.nYOff == nYOff &&
    1471                 :         sCachedMultiBandIO.nXSize == nXSize &&
    1472                 :         sCachedMultiBandIO.nYSize == nYSize &&
    1473                 :         sCachedMultiBandIO.nBufXSize == nBufXSize &&
    1474                 :         sCachedMultiBandIO.nBufYSize == nBufYSize &&
    1475                 :         sCachedMultiBandIO.eBufType == eBufType )
    1476                 :     {
    1477              11 :         sCachedMultiBandIO.nBandsTried ++;
    1478                 : 
    1479              11 :         if( sCachedMultiBandIO.bEnabled &&
    1480                 :             sCachedMultiBandIO.pabyData != NULL )
    1481                 :         {
    1482                 :             int j;
    1483               5 :             int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
    1484             255 :             for(j = 0; j < nBufYSize; j++)
    1485                 :             {
    1486                 :                 GDALCopyWords(sCachedMultiBandIO.pabyData +
    1487                 :                                     (*panBandMap - 1) * nBufXSize * nBufYSize * nDataTypeSize +
    1488                 :                                     j * nBufXSize * nDataTypeSize,
    1489                 :                             eBufType, nDataTypeSize,
    1490                 :                             ((GByte*)pData) + j * nLineSpace, eBufType, nDataTypeSize,
    1491             250 :                             nBufXSize);
    1492                 :             }
    1493               5 :             return CE_None;
    1494                 :         }
    1495                 : 
    1496               6 :         if( !(sCachedMultiBandIO.bEnabled) &&
    1497                 :             sCachedMultiBandIO.nBandsTried == nBands &&
    1498                 :             CSLTestBoolean(CPLGetConfigOption("ECW_CLEVER", "YES")) )
    1499                 :         {
    1500               3 :             sCachedMultiBandIO.bEnabled = TRUE;
    1501               3 :             CPLDebug("ECW", "Detecting successive band reading pattern (for next time)");
    1502                 :         }
    1503                 :     }
    1504                 : 
    1505                 : /* -------------------------------------------------------------------- */
    1506                 : /*      Try to do it based on existing "advised" access.                */
    1507                 : /* -------------------------------------------------------------------- */
    1508           12174 :     if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
    1509                 :                         (GByte *) pData, nBufXSize, nBufYSize, 
    1510                 :                         eBufType, nBandCount, panBandMap,
    1511                 :                         nPixelSpace, nLineSpace, nBandSpace ) )
    1512           12113 :         return CE_None;
    1513                 : 
    1514                 : /* -------------------------------------------------------------------- */
    1515                 : /*      If we are requesting a single line at 1:1, we do a multi-band   */
    1516                 : /*      AdviseRead() and then TryWinRasterIO() again.                   */
    1517                 : /*                                                                      */
    1518                 : /*      Except for reading a 1x1 window when reading a scanline might   */
    1519                 : /*      be longer.                                                      */
    1520                 : /* -------------------------------------------------------------------- */
    1521              61 :     if( nXSize == 1 && nYSize == 1 && nBufXSize == 1 && nBufYSize == 1 )
    1522                 :     {
    1523                 :         /* do nothing */
    1524                 :     }
    1525                 : 
    1526                 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
    1527                 : /* -------------------------------------------------------------------- */
    1528                 : /*      If we are supersampling we need to fall into the general        */
    1529                 : /*      purpose logic.                                                  */
    1530                 : /* -------------------------------------------------------------------- */
    1531              57 :     else if( nXSize < nBufXSize || nYSize < nBufYSize )
    1532                 :     {
    1533               1 :         bUseOldBandRasterIOImplementation = TRUE;
    1534                 :         CPLErr eErr = 
    1535                 :             GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
    1536                 :                                     pData, nBufXSize, nBufYSize,
    1537                 :                                     eBufType, 
    1538                 :                                     nBandCount, panBandMap,
    1539               1 :                                     nPixelSpace, nLineSpace, nBandSpace);
    1540               1 :         bUseOldBandRasterIOImplementation = FALSE;
    1541               1 :         return eErr;
    1542                 :     }
    1543                 : #endif
    1544                 : 
    1545              56 :     else if( nBufYSize == 1 )
    1546                 :     {
    1547                 :         //JTO: this is tricky, because it expects the rest of the image with this bufer width to be 
    1548                 :         //read. The prefered way to achieve this behaviour would be to call AdviseRead before call IRasterIO.
    1549                 :         //ERO; indeed, the logic could be improved to detect successive pattern of single line reading
    1550                 :         //before doing an AdviseRead.
    1551                 :         CPLErr eErr;
    1552                 : 
    1553                 :         eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
    1554                 :                            nBufXSize, (nRasterYSize - nYOff) / nYSize, eBufType, 
    1555              29 :                            nBandCount, panBandMap, NULL );
    1556              29 :         if( eErr == CE_None 
    1557                 :             && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
    1558                 :                                (GByte *) pData, nBufXSize, nBufYSize, 
    1559                 :                                eBufType, nBandCount, panBandMap,
    1560                 :                                nPixelSpace, nLineSpace, nBandSpace ) )
    1561              29 :             return CE_None;
    1562                 :     }
    1563                 : 
    1564                 :     CPLDebug( "ECW", 
    1565                 :               "RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.", 
    1566              31 :               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
    1567                 : 
    1568                 : /* -------------------------------------------------------------------- */
    1569                 : /*      Setup view.                                                     */
    1570                 : /* -------------------------------------------------------------------- */
    1571                 :     UINT32 anBandIndices[100];
    1572                 :     int    i;
    1573                 :     NCSError     eNCSErr;
    1574              31 :     CNCSError    oErr;
    1575                 :     
    1576              74 :     for( i = 0; i < nBandCount; i++ )
    1577              43 :         anBandIndices[i] = panBandMap[i] - 1;
    1578                 : 
    1579              31 :     CleanupWindow();
    1580                 : 
    1581                 : /* -------------------------------------------------------------------- */
    1582                 : /*      Cache data in the context of a multi-band reading pattern.      */
    1583                 : /* -------------------------------------------------------------------- */
    1584              31 :     if( nBandCount == 1 && *panBandMap == 1 && (nBands == 3 || nBands == 4) )
    1585                 :     {
    1586              14 :         if( sCachedMultiBandIO.bEnabled && sCachedMultiBandIO.nBandsTried != nBands )
    1587                 :         {
    1588               1 :             sCachedMultiBandIO.bEnabled = FALSE;
    1589               1 :             CPLDebug("ECW", "Disabling successive band reading pattern");
    1590                 :         }
    1591                 : 
    1592              14 :         sCachedMultiBandIO.nXOff = nXOff;
    1593              14 :         sCachedMultiBandIO.nYOff = nYOff;
    1594              14 :         sCachedMultiBandIO.nXSize = nXSize;
    1595              14 :         sCachedMultiBandIO.nYSize = nYSize;
    1596              14 :         sCachedMultiBandIO.nBufXSize = nBufXSize;
    1597              14 :         sCachedMultiBandIO.nBufYSize = nBufYSize;
    1598              14 :         sCachedMultiBandIO.eBufType = eBufType;
    1599              14 :         sCachedMultiBandIO.nBandsTried = 1;
    1600                 : 
    1601              14 :         int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
    1602                 : 
    1603              14 :         if( sCachedMultiBandIO.bEnabled )
    1604                 :         {
    1605                 :             GByte* pNew = (GByte*)VSIRealloc(
    1606                 :                 sCachedMultiBandIO.pabyData,
    1607               2 :                     nBufXSize * nBufYSize * nBands * nDataTypeSize);
    1608               2 :             if( pNew == NULL )
    1609               0 :                 CPLFree(sCachedMultiBandIO.pabyData);
    1610               2 :             sCachedMultiBandIO.pabyData = pNew;
    1611                 :         }
    1612                 : 
    1613              14 :         if( sCachedMultiBandIO.bEnabled &&
    1614                 :             sCachedMultiBandIO.pabyData != NULL )
    1615                 :         {
    1616               8 :             for( i = 0; i < nBands; i++ )
    1617               6 :                 anBandIndices[i] = i;
    1618                 : 
    1619                 :             oErr = poFileView->SetView( nBands, anBandIndices,
    1620                 :                                         nXOff, nYOff, 
    1621                 :                                         nXOff + nXSize - 1, 
    1622                 :                                         nYOff + nYSize - 1,
    1623               2 :                                         nBufXSize, nBufYSize );
    1624               2 :             eNCSErr = oErr.GetErrorNumber();
    1625                 : 
    1626               2 :             if( eNCSErr != NCS_SUCCESS )
    1627                 :             {
    1628                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
    1629               0 :                         "%s", NCSGetErrorText(eNCSErr) );
    1630                 : 
    1631               0 :                 return CE_Failure;
    1632                 :             }
    1633                 : 
    1634                 :             CPLErr eErr = ReadBands(sCachedMultiBandIO.pabyData,
    1635                 :                                     nBufXSize, nBufYSize, eBufType,
    1636                 :                                     nBands,
    1637                 :                                     nDataTypeSize,
    1638                 :                                     nBufXSize * nDataTypeSize,
    1639               2 :                                     nBufXSize * nBufYSize * nDataTypeSize);
    1640               2 :             if( eErr != CE_None )
    1641               0 :                 return eErr;
    1642                 : 
    1643                 :             int j;
    1644             102 :             for(j = 0; j < nBufYSize; j++)
    1645                 :             {
    1646                 :                 GDALCopyWords(sCachedMultiBandIO.pabyData +
    1647                 :                                     j * nBufXSize * nDataTypeSize,
    1648                 :                               eBufType, nDataTypeSize,
    1649                 :                               ((GByte*)pData) + j * nLineSpace, eBufType, nDataTypeSize,
    1650             100 :                               nBufXSize);
    1651                 :             }
    1652               2 :             return CE_None;
    1653                 :         }
    1654                 :     }
    1655                 : 
    1656                 :     oErr = poFileView->SetView( nBandCount, anBandIndices,
    1657                 :                                 nXOff, nYOff, 
    1658                 :                                 nXOff + nXSize - 1, 
    1659                 :                                 nYOff + nYSize - 1,
    1660              29 :                                 nBufXSize, nBufYSize );
    1661              29 :     eNCSErr = oErr.GetErrorNumber();
    1662                 :     
    1663              29 :     if( eNCSErr != NCS_SUCCESS )
    1664                 :     {
    1665                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1666               0 :                   "%s", NCSGetErrorText(eNCSErr) );
    1667                 :         
    1668               0 :         return CE_Failure;
    1669                 :     }
    1670                 : 
    1671                 :     return ReadBands(pData, nBufXSize, nBufYSize, eBufType,
    1672              29 :                      nBandCount, nPixelSpace, nLineSpace, nBandSpace);
    1673                 : }
    1674                 : 
    1675                 : /************************************************************************/
    1676                 : /*                        ReadBandsDirectly()                           */
    1677                 : /************************************************************************/
    1678                 : 
    1679              30 : CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
    1680                 :                                      GDALDataType eBufType, 
    1681                 :                                      int nBandCount,
    1682                 :                                      int nPixelSpace, int nLineSpace, int nBandSpace)
    1683                 : {
    1684                 :     CPLDebug( "ECW", 
    1685                 :               "ReadBandsDirectly(-> %dx%d) - reading lines directly.", 
    1686              30 :               nBufXSize, nBufYSize);
    1687                 : 
    1688              30 :     UINT8 **pBIL = (UINT8**)NCSMalloc(nBandCount * sizeof(UINT8*), FALSE);
    1689                 :     
    1690              74 :     for(int nB = 0; nB < nBandCount; nB++) 
    1691                 :     {
    1692              44 :         pBIL[nB] = ((UINT8*)pData) + (nBandSpace*nB);//for any bit depth
    1693                 :     }
    1694                 : 
    1695            5322 :     for(int nR = 0; nR < nBufYSize; nR++) 
    1696                 :     {
    1697            5292 :         if (poFileView->ReadLineBIL(eNCSRequestDataType,(UINT16) nBandCount, (void**)pBIL) != NCSECW_READ_OK)
    1698                 :         {
    1699               0 :             if(pBIL) {
    1700               0 :                 NCSFree(pBIL);
    1701                 :             }
    1702                 :         
    1703               0 :             return CE_Failure;
    1704                 :         }
    1705           12486 :         for(int nB = 0; nB < nBandCount; nB++) 
    1706                 :         {
    1707            7194 :             pBIL[nB] += nLineSpace;
    1708                 :         }
    1709                 :     }
    1710              30 :     if(pBIL)
    1711                 :     {
    1712              30 :         NCSFree(pBIL);
    1713                 :     }
    1714              30 :     return CE_None;
    1715                 : }
    1716                 : 
    1717                 : /************************************************************************/
    1718                 : /*                            ReadBands()                               */
    1719                 : /************************************************************************/
    1720                 : 
    1721              31 : CPLErr ECWDataset::ReadBands(void * pData, int nBufXSize, int nBufYSize,
    1722                 :                             GDALDataType eBufType, 
    1723                 :                             int nBandCount, 
    1724                 :                             int nPixelSpace, int nLineSpace, int nBandSpace)
    1725                 : {
    1726                 :     int i;
    1727                 : /* -------------------------------------------------------------------- */
    1728                 : /*      Setup working scanline, and the pointers into it.               */
    1729                 : /* -------------------------------------------------------------------- */
    1730              31 :     int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
    1731                 :     bool bDirect = (eBufType == eRasterDataType) && nDataTypeSize == nPixelSpace && 
    1732              31 :         nLineSpace == (nPixelSpace*nBufXSize) && nBandSpace == (nDataTypeSize*nBufXSize*nBufYSize) ;
    1733              31 :     if (bDirect)
    1734                 :     {
    1735                 :         return ReadBandsDirectly(pData, nBufXSize, nBufYSize,eBufType, 
    1736              30 :             nBandCount, nPixelSpace, nLineSpace, nBandSpace);
    1737                 :     }
    1738                 :      CPLDebug( "ECW", 
    1739                 :               "ReadBands(-> %dx%d) - reading lines using GDALCopyWords.", 
    1740               1 :               nBufXSize, nBufYSize);
    1741               1 :     CPLErr eErr = CE_None;
    1742                 :     GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
    1743               1 :                                                 nBandCount);
    1744               1 :     GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
    1745                 : 
    1746               4 :     for( i = 0; i < nBandCount; i++ )
    1747               3 :         papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
    1748                 : 
    1749                 : /* -------------------------------------------------------------------- */
    1750                 : /*      Read back all the data for the requested view.                  */
    1751                 : /* -------------------------------------------------------------------- */
    1752              41 :     for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
    1753                 :     {
    1754                 :         NCSEcwReadStatus  eRStatus;
    1755                 : 
    1756                 :         eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, 
    1757                 :                                             (UINT16) nBandCount,
    1758              40 :                                             (void **) papabyBIL );
    1759              40 :         if( eRStatus != NCSECW_READ_OK )
    1760                 :         {
    1761               0 :             eErr = CE_Failure;
    1762                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1763               0 :                     "NCScbmReadViewLineBIL failed." );
    1764               0 :             break;
    1765                 :         }
    1766                 : 
    1767             160 :         for( i = 0; i < nBandCount; i++ )
    1768                 :         {
    1769                 :             GDALCopyWords( 
    1770                 :                 pabyBILScanline + i * nDataTypeSize * nBufXSize,
    1771                 :                 eRasterDataType, nDataTypeSize, 
    1772                 :                 ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i, 
    1773                 :                 eBufType, nPixelSpace, 
    1774             120 :                 nBufXSize );
    1775                 :         }
    1776                 :     }
    1777                 : 
    1778               1 :     CPLFree( pabyBILScanline );
    1779               1 :     CPLFree( papabyBIL );
    1780                 : 
    1781               1 :     return eErr;
    1782                 : }
    1783                 : 
    1784                 : /************************************************************************/
    1785                 : /*                        IdentifyJPEG2000()                            */
    1786                 : /*                                                                      */
    1787                 : /*          Open method that only supports JPEG2000 files.              */
    1788                 : /************************************************************************/
    1789                 : 
    1790           12075 : int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
    1791                 : 
    1792                 : {
    1793           12075 :     if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
    1794               0 :         return TRUE;
    1795                 : 
    1796           12075 :     else if( poOpenInfo->nHeaderBytes >= 16 
    1797                 :         && (memcmp( poOpenInfo->pabyHeader, jpc_header, 
    1798                 :                     sizeof(jpc_header) ) == 0
    1799                 :             || memcmp( poOpenInfo->pabyHeader, jp2_header, 
    1800                 :                     sizeof(jp2_header) ) == 0) )
    1801              43 :         return TRUE;
    1802                 :     
    1803                 :     else
    1804           12032 :         return FALSE;
    1805                 : }
    1806                 : 
    1807                 : /************************************************************************/
    1808                 : /*                            OpenJPEG2000()                            */
    1809                 : /*                                                                      */
    1810                 : /*          Open method that only supports JPEG2000 files.              */
    1811                 : /************************************************************************/
    1812                 : 
    1813            1965 : GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
    1814                 : 
    1815                 : {
    1816            1965 :     if (!IdentifyJPEG2000(poOpenInfo))
    1817            1922 :         return NULL;
    1818                 : 
    1819              43 :     return Open( poOpenInfo, TRUE );
    1820                 : }
    1821                 :     
    1822                 : /************************************************************************/
    1823                 : /*                           IdentifyECW()                              */
    1824                 : /*                                                                      */
    1825                 : /*      Identify method that only supports ECW files.                   */
    1826                 : /************************************************************************/
    1827                 : 
    1828           12754 : int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
    1829                 : 
    1830                 : {
    1831                 : /* -------------------------------------------------------------------- */
    1832                 : /*      This has to either be a file on disk ending in .ecw or a        */
    1833                 : /*      ecwp: protocol url.                                             */
    1834                 : /* -------------------------------------------------------------------- */
    1835           12754 :     if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
    1836                 :          || poOpenInfo->nHeaderBytes == 0)
    1837                 :         && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5)
    1838                 :         && !EQUALN(poOpenInfo->pszFilename,"ecwps:",5) )
    1839           12728 :         return FALSE;
    1840                 : 
    1841              26 :     return TRUE;
    1842                 : }
    1843                 : 
    1844                 : /************************************************************************/
    1845                 : /*                              OpenECW()                               */
    1846                 : /*                                                                      */
    1847                 : /*      Open method that only supports ECW files.                       */
    1848                 : /************************************************************************/
    1849                 : 
    1850            2623 : GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
    1851                 : 
    1852                 : {
    1853            2623 :     if (!IdentifyECW(poOpenInfo))
    1854            2597 :         return NULL;
    1855                 : 
    1856              26 :     return Open( poOpenInfo, FALSE );
    1857                 : }
    1858                 : 
    1859                 : /************************************************************************/
    1860                 : /*                            OpenFileView()                            */
    1861                 : /************************************************************************/
    1862                 : 
    1863              69 : CNCSJP2FileView *ECWDataset::OpenFileView( const char *pszDatasetName,
    1864                 :                                            bool bProgressive,
    1865                 :                                            int &bUsingCustomStream, bool bWrite )
    1866                 : 
    1867                 : {
    1868                 : /* -------------------------------------------------------------------- */
    1869                 : /*      First we try to open it as a normal CNCSFile, letting the       */
    1870                 : /*      ECW SDK manage the IO itself.   This will only work for real    */
    1871                 : /*      files, and ecwp: or ecwps: sources.                             */
    1872                 : /* -------------------------------------------------------------------- */
    1873              69 :     CNCSJP2FileView *poFileView = NULL;
    1874                 :     NCSError         eErr;
    1875              69 :     CNCSError        oErr;
    1876                 : 
    1877              69 :     bUsingCustomStream = FALSE;
    1878              69 :     poFileView = new CNCSFile();
    1879                 :     //we always open in read only mode. This should be improved in the future. 
    1880             138 :     oErr = poFileView->Open( (char *) pszDatasetName, bProgressive, false );
    1881              69 :     eErr = oErr.GetErrorNumber();
    1882                 : 
    1883                 : /* -------------------------------------------------------------------- */
    1884                 : /*      If that did not work, trying opening as a virtual file.         */
    1885                 : /* -------------------------------------------------------------------- */
    1886              69 :     if( eErr != NCS_SUCCESS )
    1887                 :     {
    1888                 :         CPLDebug( "ECW", 
    1889                 :                   "NCScbmOpenFileView(%s): eErr=%d, will try VSIL stream.", 
    1890              16 :                   pszDatasetName, (int) eErr );
    1891                 : 
    1892              16 :         delete poFileView;
    1893                 : 
    1894              16 :         VSILFILE *fpVSIL = VSIFOpenL( pszDatasetName, "rb" );
    1895              16 :         if( fpVSIL == NULL )
    1896                 :         {
    1897                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1898               0 :                       "Failed to open %s.", pszDatasetName );
    1899               0 :             return NULL;
    1900                 :         }
    1901                 : 
    1902              16 :         if( hECWDatasetMutex == NULL )
    1903                 :         {
    1904               0 :             hECWDatasetMutex = CPLCreateMutex();
    1905                 :         }
    1906              16 :         else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
    1907                 :         {
    1908               0 :             CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
    1909                 :         }
    1910                 :         else
    1911                 :         {
    1912              16 :             CPLDebug( "ECW", "Got mutex." );
    1913                 :         }
    1914              16 :         VSIIOStream *poIOStream = new VSIIOStream();
    1915              32 :         poIOStream->Access( fpVSIL, FALSE, pszDatasetName, 0, -1 );
    1916                 : 
    1917              16 :         poFileView = new CNCSJP2FileView();
    1918              32 :         oErr = poFileView->Open( poIOStream, bProgressive );
    1919                 : 
    1920                 :         // The CNCSJP2FileView (poFileView) object may not use the iostream 
    1921                 :         // (poIOStream) passed to the CNCSJP2FileView::Open() method if an 
    1922                 :         // iostream is already available to the ECW JPEG 2000 SDK for a given
    1923                 :         // file.  Consequently, if the iostream passed to 
    1924                 :         // CNCSJP2FileView::Open() does not become the underlying iostream 
    1925                 :         // of the CNCSJP2FileView object, then it should be deleted.
    1926                 :         //
    1927                 :         // In addition, the underlying iostream of the CNCSJP2FileView object
    1928                 :         // should not be deleted until all CNCSJP2FileView objects using the 
    1929                 :         // underlying iostream are deleted. Consequently, each time a 
    1930                 :         // CNCSJP2FileView object is created, the nFileViewCount attribute 
    1931                 :         // of the underlying VSIIOStream object must be incremented for use 
    1932                 :         // in the ECWDataset destructor.
    1933                 :           
    1934                 :         VSIIOStream * poUnderlyingIOStream = 
    1935              16 :             ((VSIIOStream *)(poFileView->GetStream()));
    1936                 : 
    1937              16 :         if ( poUnderlyingIOStream )
    1938              15 :             poUnderlyingIOStream->nFileViewCount++;
    1939                 : 
    1940              16 :         if ( poIOStream != poUnderlyingIOStream ) 
    1941                 :         {
    1942               1 :             delete poIOStream;
    1943                 :         }
    1944                 :         else
    1945                 :         {
    1946              15 :             bUsingCustomStream = TRUE;
    1947                 :         }
    1948                 : 
    1949              16 :         CPLReleaseMutex( hECWDatasetMutex );
    1950                 : 
    1951              16 :         if( oErr.GetErrorNumber() != NCS_SUCCESS )
    1952                 :         {
    1953               1 :             if (poFileView)
    1954               1 :                 delete poFileView;
    1955               1 :             ECWReportError(oErr);
    1956                 : 
    1957               1 :             return NULL;
    1958                 :         }
    1959                 :     }
    1960                 :     
    1961              68 :     return poFileView;
    1962                 : }
    1963                 : 
    1964                 : /************************************************************************/
    1965                 : /*                                Open()                                */
    1966                 : /************************************************************************/
    1967                 : 
    1968              69 : GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
    1969                 : 
    1970                 : {
    1971              69 :     CNCSJP2FileView *poFileView = NULL;
    1972                 :     int              i;
    1973              69 :     int              bUsingCustomStream = FALSE;
    1974              69 :     CPLString        osFilename = poOpenInfo->pszFilename;
    1975                 : 
    1976              69 :     ECWInitialize();
    1977                 : 
    1978                 : /* -------------------------------------------------------------------- */
    1979                 : /*      If we get a J2K_SUBFILE style name, convert it into the         */
    1980                 : /*      corresponding /vsisubfile/ path.                                */
    1981                 : /*                                                                      */
    1982                 : /*      From: J2K_SUBFILE:offset,size,filename                           */
    1983                 : /*      To: /vsisubfile/offset_size,filename                            */
    1984                 : /* -------------------------------------------------------------------- */
    1985              69 :     if (EQUALN(osFilename,"J2K_SUBFILE:",12))
    1986                 :     {
    1987               0 :         char** papszTokens = CSLTokenizeString2(osFilename.c_str()+12, ",", 0);
    1988               0 :         if (CSLCount(papszTokens) >= 2)
    1989                 :         {
    1990                 :             osFilename.Printf( "/vsisubfile/%s_%s,%s",
    1991               0 :                                papszTokens[0], papszTokens[1], papszTokens[2]);
    1992                 :         }
    1993                 :         else
    1994                 :         {
    1995                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1996               0 :                       "Failed to parse J2K_SUBFILE specification." );
    1997               0 :             CSLDestroy(papszTokens);
    1998               0 :             return NULL;
    1999                 :         }
    2000               0 :         CSLDestroy(papszTokens);
    2001                 :     }
    2002                 : 
    2003                 : /* -------------------------------------------------------------------- */
    2004                 : /*      Open the client interface.                                      */
    2005                 : /* -------------------------------------------------------------------- */
    2006              69 :     poFileView = OpenFileView( osFilename.c_str(), false, bUsingCustomStream, poOpenInfo->eAccess == GA_Update );
    2007              69 :     if( poFileView == NULL )
    2008               1 :         return NULL;
    2009                 : 
    2010                 : /* -------------------------------------------------------------------- */
    2011                 : /*      Create a corresponding GDALDataset.                             */
    2012                 : /* -------------------------------------------------------------------- */
    2013                 :     ECWDataset  *poDS;
    2014                 : 
    2015              68 :     poDS = new ECWDataset(bIsJPEG2000);
    2016              68 :     poDS->poFileView = poFileView;
    2017              68 :     poDS->eAccess = poOpenInfo->eAccess;
    2018                 : 
    2019                 :     // Disable .aux.xml writing for subfiles and such.  Unfortunately
    2020                 :     // this will also disable it in some cases where it might be 
    2021                 :     // applicable. 
    2022              68 :     if( bUsingCustomStream )
    2023              15 :         poDS->nPamFlags |= GPF_DISABLED;
    2024                 : 
    2025              68 :     poDS->bUsingCustomStream = bUsingCustomStream;
    2026                 : 
    2027                 : /* -------------------------------------------------------------------- */
    2028                 : /*      Fetch general file information.                                 */
    2029                 : /* -------------------------------------------------------------------- */
    2030              68 :     poDS->psFileInfo = poFileView->GetFileInfo();
    2031                 : 
    2032                 :     CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
    2033                 :               "       OriginXY=%g,%g  CellIncrementXY=%g,%g\n"
    2034                 :               "       ColorSpace=%d, eCellType=%d\n", 
    2035                 :               poDS->psFileInfo->nSizeX,
    2036                 :               poDS->psFileInfo->nSizeY,
    2037                 :               poDS->psFileInfo->nBands,
    2038                 :               poDS->psFileInfo->fOriginX,
    2039                 :               poDS->psFileInfo->fOriginY,
    2040                 :               poDS->psFileInfo->fCellIncrementX,
    2041                 :               poDS->psFileInfo->fCellIncrementY,
    2042                 :               (int) poDS->psFileInfo->eColorSpace,
    2043              68 :               (int) poDS->psFileInfo->eCellType );
    2044                 : 
    2045                 : /* -------------------------------------------------------------------- */
    2046                 : /*      Establish raster info.                                          */
    2047                 : /* -------------------------------------------------------------------- */
    2048              68 :     poDS->nRasterXSize = poDS->psFileInfo->nSizeX; 
    2049              68 :     poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
    2050                 : 
    2051                 : /* -------------------------------------------------------------------- */
    2052                 : /*      Establish the GDAL data type that corresponds.  A few NCS       */
    2053                 : /*      data types have no direct corresponding value in GDAL so we     */
    2054                 : /*      will coerce to something sufficiently similar.                  */
    2055                 : /* -------------------------------------------------------------------- */
    2056              68 :     poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
    2057              68 :     switch( poDS->psFileInfo->eCellType )
    2058                 :     {
    2059                 :         case NCSCT_UINT8:
    2060              57 :             poDS->eRasterDataType = GDT_Byte;
    2061              57 :             break;
    2062                 : 
    2063                 :         case NCSCT_UINT16:
    2064               5 :             poDS->eRasterDataType = GDT_UInt16;
    2065               5 :             break;
    2066                 : 
    2067                 :         case NCSCT_UINT32:
    2068                 :         case NCSCT_UINT64:
    2069               1 :             poDS->eRasterDataType = GDT_UInt32;
    2070               1 :             poDS->eNCSRequestDataType = NCSCT_UINT32;
    2071               1 :             break;
    2072                 : 
    2073                 :         case NCSCT_INT8:
    2074                 :         case NCSCT_INT16:
    2075               3 :             poDS->eRasterDataType = GDT_Int16;
    2076               3 :             poDS->eNCSRequestDataType = NCSCT_INT16;
    2077               3 :             break;
    2078                 : 
    2079                 :         case NCSCT_INT32:
    2080                 :         case NCSCT_INT64:
    2081               2 :             poDS->eRasterDataType = GDT_Int32;
    2082               2 :             poDS->eNCSRequestDataType = NCSCT_INT32;
    2083               2 :             break;
    2084                 : 
    2085                 :         case NCSCT_IEEE4:
    2086               0 :             poDS->eRasterDataType = GDT_Float32;
    2087               0 :             break;
    2088                 : 
    2089                 :         case NCSCT_IEEE8:
    2090               0 :             poDS->eRasterDataType = GDT_Float64;
    2091                 :             break;
    2092                 :     }
    2093                 : 
    2094                 : /* -------------------------------------------------------------------- */
    2095                 : /*      Create band information objects.                                */
    2096                 : /* -------------------------------------------------------------------- */
    2097             206 :     for( i=0; i < poDS->psFileInfo->nBands; i++ )
    2098             138 :         poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
    2099                 : 
    2100                 : /* -------------------------------------------------------------------- */
    2101                 : /*      Look for supporting coordinate system information.              */
    2102                 : /* -------------------------------------------------------------------- */
    2103              68 :     if( bIsJPEG2000 )
    2104                 :     {
    2105              43 :         GDALJP2Metadata oJP2Geo;
    2106              43 :         if ( oJP2Geo.ReadAndParse( osFilename ) )
    2107                 :         {
    2108              25 :             poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
    2109              25 :             poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
    2110                 :             memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
    2111              25 :                     sizeof(double) * 6 );
    2112              25 :             poDS->nGCPCount = oJP2Geo.nGCPCount;
    2113              25 :             poDS->pasGCPList = oJP2Geo.pasGCPList;
    2114              25 :             oJP2Geo.pasGCPList = NULL;
    2115              25 :             oJP2Geo.nGCPCount = 0;
    2116                 :         }
    2117                 : 
    2118              43 :         if (oJP2Geo.pszXMPMetadata)
    2119                 :         {
    2120                 :             char *apszMDList[2];
    2121               1 :             apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
    2122               1 :             apszMDList[1] = NULL;
    2123               1 :             poDS->SetMetadata(apszMDList, "xml:XMP");
    2124              43 :         }
    2125                 :     }
    2126                 :     else
    2127                 :     {
    2128              25 :         poDS->ECW2WKTProjection();
    2129                 :     }
    2130                 : 
    2131                 : /* -------------------------------------------------------------------- */
    2132                 : /*      Check for world file.                                           */
    2133                 : /* -------------------------------------------------------------------- */
    2134              68 :     if( !poDS->bGeoTransformValid )
    2135                 :     {
    2136                 :         poDS->bGeoTransformValid |= 
    2137                 :             GDALReadWorldFile2( osFilename, NULL,
    2138                 :                                 poDS->adfGeoTransform,
    2139                 :                                 poOpenInfo->papszSiblingFiles, NULL )
    2140                 :             || GDALReadWorldFile2( osFilename, ".wld",
    2141                 :                                    poDS->adfGeoTransform,
    2142              22 :                                    poOpenInfo->papszSiblingFiles, NULL );
    2143                 :     }
    2144                 : 
    2145                 : /* -------------------------------------------------------------------- */
    2146                 : /*      Initialize any PAM information.                                 */
    2147                 : /* -------------------------------------------------------------------- */
    2148              68 :     poDS->SetDescription( osFilename );
    2149              68 :     poDS->TryLoadXML();
    2150                 :     
    2151              68 :     return( poDS );
    2152                 : }
    2153                 : 
    2154                 : /************************************************************************/
    2155                 : /*                            GetGCPCount()                             */
    2156                 : /************************************************************************/
    2157                 : 
    2158               7 : int ECWDataset::GetGCPCount()
    2159                 : 
    2160                 : {
    2161               7 :     if( nGCPCount != 0 )
    2162               3 :         return nGCPCount;
    2163                 :     else
    2164               4 :         return GDALPamDataset::GetGCPCount();
    2165                 : }
    2166                 : 
    2167                 : /************************************************************************/
    2168                 : /*                          GetGCPProjection()                          */
    2169                 : /************************************************************************/
    2170                 : 
    2171               2 : const char *ECWDataset::GetGCPProjection()
    2172                 : 
    2173                 : {
    2174               2 :     if( nGCPCount > 0 )
    2175               2 :         return pszProjection;
    2176                 :     else
    2177               0 :         return GDALPamDataset::GetGCPProjection();
    2178                 : }
    2179                 : 
    2180                 : /************************************************************************/
    2181                 : /*                               GetGCP()                               */
    2182                 : /************************************************************************/
    2183                 : 
    2184               3 : const GDAL_GCP *ECWDataset::GetGCPs()
    2185                 : 
    2186                 : {
    2187               3 :     if( nGCPCount != 0 )
    2188               2 :         return pasGCPList;
    2189                 :     else
    2190               1 :         return GDALPamDataset::GetGCPs();
    2191                 : }
    2192                 : 
    2193                 : /************************************************************************/
    2194                 : /*                          GetProjectionRef()                          */
    2195                 : /*                                                                      */
    2196                 : /*      We let PAM coordinate system override the one stored inside     */
    2197                 : /*      our file.                                                       */
    2198                 : /************************************************************************/
    2199                 : 
    2200              43 : const char *ECWDataset::GetProjectionRef() 
    2201                 : 
    2202                 : {
    2203              43 :     const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
    2204                 : 
    2205              43 :     if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
    2206              28 :         return pszProjection;
    2207                 :     else
    2208              15 :         return pszPamPrj;
    2209                 : }
    2210                 : 
    2211                 : /************************************************************************/
    2212                 : /*                          GetGeoTransform()                           */
    2213                 : /*                                                                      */
    2214                 : /*      Let the PAM geotransform override the native one if it is       */
    2215                 : /*      available.                                                      */
    2216                 : /************************************************************************/
    2217                 : 
    2218              29 : CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
    2219                 : 
    2220                 : {
    2221              29 :     CPLErr eErr = GDALPamDataset::GetGeoTransform( padfTransform );
    2222                 : 
    2223              29 :     if( eErr != CE_None && bGeoTransformValid )
    2224                 :     {
    2225              24 :         memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
    2226              24 :         return( CE_None );
    2227                 :     }
    2228                 :     else
    2229               5 :         return eErr;
    2230                 : }
    2231                 : 
    2232                 : /************************************************************************/
    2233                 : /*                           GetMetadataItem()                          */
    2234                 : /************************************************************************/
    2235                 : 
    2236              14 : const char *ECWDataset::GetMetadataItem( const char * pszName,
    2237                 :                                          const char * pszDomain )
    2238                 : {
    2239              14 :     if (!bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") && pszName != NULL)
    2240                 :     {
    2241               6 :         if (EQUAL(pszName, "PROJ"))
    2242               2 :             return m_osProjCode.size() ? m_osProjCode.c_str() : "RAW";
    2243               4 :         if (EQUAL(pszName, "DATUM"))
    2244               2 :             return m_osDatumCode.size() ? m_osDatumCode.c_str() : "RAW";
    2245               2 :         if (EQUAL(pszName, "UNITS"))
    2246               2 :             return m_osUnitsCode.size() ? m_osUnitsCode.c_str() : "METERS";
    2247                 :     }
    2248               8 :     return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
    2249                 : }
    2250                 : 
    2251                 : /************************************************************************/
    2252                 : /*                            GetMetadata()                             */
    2253                 : /************************************************************************/
    2254                 : 
    2255              20 : char **ECWDataset::GetMetadata( const char *pszDomain )
    2256                 : 
    2257                 : {
    2258              20 :     if( !bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") )
    2259                 :     {
    2260               0 :         oECWMetadataList.Clear();
    2261               0 :         oECWMetadataList.AddString(CPLSPrintf("%s=%s", "PROJ", GetMetadataItem("PROJ", "ECW")));
    2262               0 :         oECWMetadataList.AddString(CPLSPrintf("%s=%s", "DATUM", GetMetadataItem("DATUM", "ECW")));
    2263               0 :         oECWMetadataList.AddString(CPLSPrintf("%s=%s", "UNITS", GetMetadataItem("UNITS", "ECW")));
    2264               0 :         return oECWMetadataList.List();
    2265                 :     }
    2266              20 :     else if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
    2267              20 :         return GDALPamDataset::GetMetadata( pszDomain );
    2268                 :     else
    2269               0 :         return papszGMLMetadata;
    2270                 : }
    2271                 : 
    2272                 : /************************************************************************/
    2273                 : /*                         ECW2WKTProjection()                          */
    2274                 : /*                                                                      */
    2275                 : /*      Set the dataset pszProjection string in OGC WKT format by       */
    2276                 : /*      looking up the ECW (GDT) coordinate system info in              */
    2277                 : /*      ecw_cs.dat support data file.                                   */
    2278                 : /*                                                                      */
    2279                 : /*      This code is likely still broken in some circumstances.  For    */
    2280                 : /*      instance, I haven't been careful about changing the linear      */
    2281                 : /*      projection parameters (false easting/northing) if the units     */
    2282                 : /*      is feet.  Lots of cases missing here, and in ecw_cs.dat.        */
    2283                 : /************************************************************************/
    2284                 : 
    2285              25 : void ECWDataset::ECW2WKTProjection()
    2286                 : 
    2287                 : {
    2288              25 :     if( psFileInfo == NULL )
    2289               0 :         return;
    2290                 : 
    2291                 : /* -------------------------------------------------------------------- */
    2292                 : /*      Capture Geotransform.                                           */
    2293                 : /*                                                                      */
    2294                 : /*      We will try to ignore the provided file information if it is    */
    2295                 : /*      origin (0,0) and pixel size (1,1).  I think sometimes I have    */
    2296                 : /*      also seen pixel increments of 0 on invalid datasets.            */
    2297                 : /* -------------------------------------------------------------------- */
    2298              25 :     if( psFileInfo->fOriginX != 0.0 
    2299                 :         || psFileInfo->fOriginY != 0.0 
    2300                 :         || (psFileInfo->fCellIncrementX != 0.0 
    2301                 :             && psFileInfo->fCellIncrementX != 1.0)
    2302                 :         || (psFileInfo->fCellIncrementY != 0.0 
    2303                 :             && psFileInfo->fCellIncrementY != 1.0) )
    2304                 :     {
    2305              25 :         bGeoTransformValid = TRUE;
    2306                 :         
    2307              25 :         adfGeoTransform[0] = psFileInfo->fOriginX;
    2308              25 :         adfGeoTransform[1] = psFileInfo->fCellIncrementX;
    2309              25 :         adfGeoTransform[2] = 0.0;
    2310                 :         
    2311              25 :         adfGeoTransform[3] = psFileInfo->fOriginY;
    2312              25 :         adfGeoTransform[4] = 0.0;
    2313              25 :         adfGeoTransform[5] = -fabs(psFileInfo->fCellIncrementY);
    2314                 :     }
    2315                 : 
    2316                 : /* -------------------------------------------------------------------- */
    2317                 : /*      do we have projection and datum?                                */
    2318                 : /* -------------------------------------------------------------------- */
    2319              25 :     CPLString osUnits = ECWTranslateFromCellSizeUnits(psFileInfo->eCellSizeUnits);
    2320                 : 
    2321                 :     CPLDebug( "ECW", "projection=%s, datum=%s, units=%s",
    2322                 :               psFileInfo->szProjection, psFileInfo->szDatum,
    2323              25 :               osUnits.c_str());
    2324                 : 
    2325              25 :     if( EQUAL(psFileInfo->szProjection,"RAW") )
    2326                 :         return;
    2327                 : 
    2328                 : /* -------------------------------------------------------------------- */
    2329                 : /*      Set projection if we have it.                                   */
    2330                 : /* -------------------------------------------------------------------- */
    2331               9 :     OGRSpatialReference oSRS;
    2332                 : 
    2333                 :     /* For backward-compatible with previous behaviour. Should we only */
    2334                 :     /* restrict to those 2 values ? */
    2335               9 :     if (psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_METERS &&
    2336                 :         psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_FEET)
    2337               0 :         osUnits = ECWTranslateFromCellSizeUnits(ECW_CELL_UNITS_METERS);
    2338                 : 
    2339               9 :     m_osDatumCode = psFileInfo->szDatum;
    2340               9 :     m_osProjCode = psFileInfo->szProjection;
    2341               9 :     m_osUnitsCode = osUnits;
    2342               9 :     if( oSRS.importFromERM( psFileInfo->szProjection, 
    2343                 :                             psFileInfo->szDatum, 
    2344                 :                             osUnits ) == OGRERR_NONE )
    2345                 :     {
    2346               9 :         oSRS.exportToWkt( &pszProjection );
    2347                 :     }
    2348                 : 
    2349               9 :     CPLErrorReset(); /* see #4187 */
    2350                 : }
    2351                 : 
    2352                 : /************************************************************************/
    2353                 : /*                        ECWTranslateFromWKT()                         */
    2354                 : /************************************************************************/
    2355                 : 
    2356              24 : int ECWTranslateFromWKT( const char *pszWKT,
    2357                 :                          char *pszProjection,
    2358                 :                          int nProjectionLen,
    2359                 :                          char *pszDatum,
    2360                 :                          int nDatumLen,
    2361                 :                          char *pszUnits)
    2362                 : 
    2363                 : {
    2364              24 :     OGRSpatialReference oSRS;
    2365              24 :     char *pszWKTIn = (char *) pszWKT;
    2366                 : 
    2367              24 :     strcpy( pszProjection, "RAW" );
    2368              24 :     strcpy( pszDatum, "RAW" );
    2369              24 :     strcpy( pszUnits, "METERS" );
    2370                 : 
    2371              24 :     if( pszWKT == NULL || strlen(pszWKT) == 0 )
    2372               1 :         return FALSE;
    2373                 :     
    2374              23 :     oSRS.importFromWkt( &pszWKTIn );
    2375                 :     
    2376              23 :     if( oSRS.IsLocal() )
    2377               0 :         return TRUE;
    2378                 : 
    2379                 : /* -------------------------------------------------------------------- */
    2380                 : /*      Do we have an overall EPSG number for this coordinate system?   */
    2381                 : /* -------------------------------------------------------------------- */
    2382              23 :     const char *pszAuthorityCode = NULL;
    2383              23 :     const char *pszAuthorityName = NULL;
    2384              23 :     UINT32 nEPSGCode = 0;
    2385                 : 
    2386              23 :     if( oSRS.IsProjected() )
    2387                 :     {
    2388               6 :         pszAuthorityCode =  oSRS.GetAuthorityCode( "PROJCS" );
    2389               6 :         pszAuthorityName =  oSRS.GetAuthorityName( "PROJCS" );
    2390                 :     }
    2391              17 :     else if( oSRS.IsGeographic() )
    2392                 :     {
    2393              17 :         pszAuthorityCode =  oSRS.GetAuthorityCode( "GEOGCS" );
    2394              17 :         pszAuthorityName =  oSRS.GetAuthorityName( "GEOGCS" );
    2395                 :     }
    2396                 : 
    2397              23 :     if( pszAuthorityName != NULL && EQUAL(pszAuthorityName,"EPSG") 
    2398                 :         && pszAuthorityCode != NULL && atoi(pszAuthorityCode) > 0 )
    2399              18 :         nEPSGCode = (UINT32) atoi(pszAuthorityCode);
    2400                 : 
    2401              23 :     if( nEPSGCode != 0 )
    2402                 :     {
    2403              18 :         char *pszEPSGProj = NULL, *pszEPSGDatum = NULL;
    2404              18 :         CNCSError oErr;
    2405                 : 
    2406                 :         oErr = 
    2407                 :             CNCSJP2FileView::GetProjectionAndDatum( atoi(pszAuthorityCode), 
    2408              18 :                                                  &pszEPSGProj, &pszEPSGDatum );
    2409                 : 
    2410                 :         CPLDebug( "ECW", "GetGDTProjDat(%d) = %s/%s", 
    2411              18 :                   atoi(pszAuthorityCode), pszEPSGProj, pszEPSGDatum );
    2412                 : 
    2413              18 :         if( oErr.GetErrorNumber() == NCS_SUCCESS
    2414                 :             && pszEPSGProj != NULL && pszEPSGDatum != NULL )
    2415                 :         {
    2416              18 :             strncpy( pszProjection, pszEPSGProj, nProjectionLen );
    2417              18 :             strncpy( pszDatum, pszEPSGDatum, nDatumLen );
    2418              18 :             pszProjection[nProjectionLen - 1] = 0;
    2419              18 :             pszDatum[nDatumLen - 1] = 0;
    2420              18 :             NCSFree( pszEPSGProj );
    2421              18 :             NCSFree( pszEPSGDatum );
    2422              18 :             return TRUE;
    2423                 :         }
    2424                 : 
    2425               0 :         NCSFree( pszEPSGProj );
    2426               0 :         NCSFree( pszEPSGDatum );
    2427                 : 
    2428                 :     }
    2429                 : 
    2430                 : /* -------------------------------------------------------------------- */
    2431                 : /*      Fallback to translating based on the ecw_cs.wkt file, and       */
    2432                 : /*      various jiffy rules.                                            */
    2433                 : /* -------------------------------------------------------------------- */
    2434                 : 
    2435               5 :     return oSRS.exportToERM( pszProjection, pszDatum, pszUnits ) == OGRERR_NONE;
    2436                 : }
    2437                 : 
    2438                 : /************************************************************************/
    2439                 : /*                    ECWTranslateToCellSizeUnits()                     */
    2440                 : /************************************************************************/
    2441                 : 
    2442              25 : CellSizeUnits ECWTranslateToCellSizeUnits(const char* pszUnits)
    2443                 : {
    2444              25 :     if (EQUAL(pszUnits, "METERS"))
    2445              23 :         return ECW_CELL_UNITS_METERS;
    2446               2 :     else if (EQUAL(pszUnits, "DEGREES"))
    2447               0 :         return ECW_CELL_UNITS_DEGREES;
    2448               2 :     else if (EQUAL(pszUnits, "FEET"))
    2449               2 :         return ECW_CELL_UNITS_FEET;
    2450               0 :     else if (EQUAL(pszUnits, "UNKNOWN"))
    2451               0 :         return ECW_CELL_UNITS_UNKNOWN;
    2452               0 :     else if (EQUAL(pszUnits, "INVALID"))
    2453               0 :         return ECW_CELL_UNITS_INVALID;
    2454                 :     else
    2455                 :     {
    2456               0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized value for UNITS : %s", pszUnits);
    2457               0 :         return ECW_CELL_UNITS_INVALID;
    2458                 :     }
    2459                 : }
    2460                 : 
    2461                 : /************************************************************************/
    2462                 : /*                   ECWGetColorInterpretationByName()                  */
    2463                 : /************************************************************************/
    2464                 : 
    2465              28 : GDALColorInterp ECWGetColorInterpretationByName(const char *pszName)
    2466                 : {
    2467              28 :     if (EQUAL(pszName, NCS_BANDDESC_AllOpacity)) 
    2468               1 :         return GCI_AlphaBand;
    2469              27 :     else if (EQUAL(pszName, NCS_BANDDESC_Blue))
    2470               0 :         return GCI_BlueBand;
    2471              27 :     else if (EQUAL(pszName, NCS_BANDDESC_Green))
    2472               0 :         return GCI_GreenBand;
    2473              27 :     else if (EQUAL(pszName, NCS_BANDDESC_Red))
    2474               0 :         return GCI_RedBand;
    2475              27 :     else if (EQUAL(pszName, NCS_BANDDESC_Greyscale))
    2476               0 :         return GCI_GrayIndex;
    2477              27 :     else if (EQUAL(pszName, NCS_BANDDESC_GreyscaleOpacity))
    2478               0 :         return GCI_AlphaBand;
    2479              27 :     return GCI_Undefined;
    2480                 : }
    2481                 : 
    2482                 : /************************************************************************/
    2483                 : /*                    ECWGetColorInterpretationName()                   */
    2484                 : /************************************************************************/
    2485                 : 
    2486              40 : const char* ECWGetColorInterpretationName(GDALColorInterp eColorInterpretation, int nBandNumber)
    2487                 : {
    2488                 :     const char *result;
    2489              40 :     switch (eColorInterpretation){
    2490                 :     case GCI_AlphaBand: 
    2491               1 :         result = NCS_BANDDESC_AllOpacity;
    2492               1 :         break;
    2493                 :     case GCI_GrayIndex: 
    2494              19 :         result = NCS_BANDDESC_Greyscale;
    2495              19 :         break;
    2496                 :     case GCI_RedBand:
    2497                 :     case GCI_GreenBand:
    2498                 :     case GCI_BlueBand: 
    2499              15 :         result = GDALGetColorInterpretationName(eColorInterpretation);
    2500              15 :         break;
    2501                 :     case GCI_Undefined:
    2502               5 :         if (nBandNumber <=3){
    2503               4 :             if (nBandNumber == 0 ) {
    2504               0 :                 result = "Red";
    2505               4 :             }else if (nBandNumber == 1) {
    2506               2 :                 result = "Green";
    2507               2 :             }else if (nBandNumber == 2) {
    2508               1 :                 result = "Blue";
    2509                 :             }
    2510                 :         }
    2511               5 :         result = CPLSPrintf(NCS_BANDDESC_Band,nBandNumber + 1);
    2512               5 :         break;
    2513                 :     default: 
    2514               0 :         result = CPLSPrintf(NCS_BANDDESC_Band,nBandNumber + 1);
    2515                 :     }
    2516              40 :     return result;
    2517                 : }
    2518                 : 
    2519                 : /************************************************************************/
    2520                 : /*                     ECWTranslateFromCellSizeUnits()                  */
    2521                 : /************************************************************************/
    2522                 : 
    2523              51 : const char* ECWTranslateFromCellSizeUnits(CellSizeUnits eUnits)
    2524                 : {
    2525              51 :     if (eUnits == ECW_CELL_UNITS_METERS)
    2526              47 :         return "METERS";
    2527               4 :     else if (eUnits == ECW_CELL_UNITS_DEGREES)
    2528               0 :         return "DEGREES";
    2529               4 :     else if (eUnits == ECW_CELL_UNITS_FEET)
    2530               4 :         return "FEET";
    2531               0 :     else if (eUnits == ECW_CELL_UNITS_UNKNOWN)
    2532               0 :         return "UNKNOWN";
    2533                 :     else
    2534               0 :         return "INVALID";
    2535                 : }
    2536                 : 
    2537                 : #endif /* def FRMT_ecw */
    2538                 : 
    2539                 : /************************************************************************/
    2540                 : /*                           ECWInitialize()                            */
    2541                 : /*                                                                      */
    2542                 : /*      Initialize NCS library.  We try to defer this as late as        */
    2543                 : /*      possible since de-initializing it seems to be expensive/slow    */
    2544                 : /*      on some system.                                                 */
    2545                 : /************************************************************************/
    2546                 : 
    2547             119 : void ECWInitialize()
    2548                 : 
    2549                 : {
    2550             119 :     CPLMutexHolder oHolder( &hECWDatasetMutex );
    2551                 : 
    2552             119 :     if( bNCSInitialized )
    2553                 :         return;
    2554                 : 
    2555                 : #ifndef WIN32
    2556               3 :     NCSecwInit();
    2557                 : #endif
    2558               3 :     bNCSInitialized = TRUE;
    2559                 : 
    2560                 : /* -------------------------------------------------------------------- */
    2561                 : /*      This will disable automatic conversion of YCbCr to RGB by       */
    2562                 : /*      the toolkit.                                                    */
    2563                 : /* -------------------------------------------------------------------- */
    2564               3 :     if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
    2565               0 :         NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
    2566                 : #if ECWSDK_VERSION>= 50
    2567                 :   NCSecwSetConfig(NCSCFG_ECWP_CLIENT_HTTP_USER_AGENT, "ECW GDAL Driver/" NCS_ECWJP2_FULL_VERSION_STRING_DOT_DEL);
    2568                 : #endif 
    2569                 : /* -------------------------------------------------------------------- */
    2570                 : /*      Initialize cache memory limit.  Default is apparently 1/4 RAM.  */
    2571                 : /* -------------------------------------------------------------------- */
    2572                 :     const char *pszEcwCacheSize = 
    2573               3 :         CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
    2574               3 :     if( pszEcwCacheSize == NULL )
    2575               3 :         pszEcwCacheSize = CPLGetConfigOption("ECW_CACHE_MAXMEM",NULL);
    2576                 : 
    2577               3 :     if( pszEcwCacheSize != NULL )
    2578               0 :         NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, (UINT32) atoi(pszEcwCacheSize) );
    2579                 : 
    2580                 :     /* -------------------------------------------------------------------- */
    2581                 :     /*      Version 3.x and 4.x of the ECWJP2 SDK did not resolve datum and         */
    2582                 :     /*      projection to EPSG code using internal mapping.         */
    2583                 :     /*    Version 5.x do so we provide means to achieve old   */
    2584                 :     /*    behaviour.                            */
    2585                 :     /* -------------------------------------------------------------------- */
    2586                 :     #if ECWSDK_VERSION >= 50
    2587                 :     if( CSLTestBoolean( CPLGetConfigOption("ECW_DO_NOT_RESOLVE_DATUM_PROJECTION","NO") ) == TRUE) 
    2588                 :         NCSecwSetConfig(NCSCFG_PROJECTION_FORMAT, NCS_PROJECTION_ERMAPPER_FORMAT);
    2589                 :     #endif
    2590                 : /* -------------------------------------------------------------------- */
    2591                 : /*      Allow configuration of a local cache based on configuration     */
    2592                 : /*      options.  Setting the location turns things on.                 */
    2593                 : /* -------------------------------------------------------------------- */
    2594                 :     const char *pszOpt;
    2595                 : 
    2596                 : #if ECWSDK_VERSION >= 40
    2597                 :     pszOpt = CPLGetConfigOption( "ECWP_CACHE_SIZE_MB", NULL );
    2598                 :     if( pszOpt )
    2599                 :         NCSecwSetConfig( NCSCFG_ECWP_CACHE_SIZE_MB, (INT32) atoi( pszOpt ) );
    2600                 : 
    2601                 :     pszOpt = CPLGetConfigOption( "ECWP_CACHE_LOCATION", NULL );
    2602                 :     if( pszOpt )
    2603                 :     {
    2604                 :         NCSecwSetConfig( NCSCFG_ECWP_CACHE_LOCATION, pszOpt );
    2605                 :         NCSecwSetConfig( NCSCFG_ECWP_CACHE_ENABLED, (BOOLEAN) TRUE );
    2606                 :     }
    2607                 : #endif
    2608                 : 
    2609                 : /* -------------------------------------------------------------------- */
    2610                 : /*      Various other configuration items.                              */
    2611                 : /* -------------------------------------------------------------------- */
    2612               3 :     pszOpt = CPLGetConfigOption( "ECWP_BLOCKING_TIME_MS", NULL );
    2613               3 :     if( pszOpt )
    2614                 :         NCSecwSetConfig( NCSCFG_BLOCKING_TIME_MS, 
    2615               0 :                          (NCSTimeStampMs) atoi(pszOpt) );
    2616                 : 
    2617                 :     // I believe 10s means we wait for complete data back from
    2618                 :     // ECWP almost all the time which is good for our blocking model.
    2619               3 :     pszOpt = CPLGetConfigOption( "ECWP_REFRESH_TIME_MS", "10000" );
    2620               3 :     if( pszOpt )
    2621                 :         NCSecwSetConfig( NCSCFG_REFRESH_TIME_MS, 
    2622               3 :                          (NCSTimeStampMs) atoi(pszOpt) );
    2623                 : 
    2624               3 :     pszOpt = CPLGetConfigOption( "ECW_TEXTURE_DITHER", NULL );
    2625               3 :     if( pszOpt )
    2626                 :         NCSecwSetConfig( NCSCFG_TEXTURE_DITHER, 
    2627               0 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    2628                 : 
    2629                 : 
    2630               3 :     pszOpt = CPLGetConfigOption( "ECW_FORCE_FILE_REOPEN", NULL );
    2631               3 :     if( pszOpt )
    2632                 :         NCSecwSetConfig( NCSCFG_FORCE_FILE_REOPEN, 
    2633               0 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    2634                 : 
    2635               3 :     pszOpt = CPLGetConfigOption( "ECW_CACHE_MAXOPEN", NULL );
    2636               3 :     if( pszOpt )
    2637               0 :         NCSecwSetConfig( NCSCFG_CACHE_MAXOPEN, (UINT32) atoi(pszOpt) );
    2638                 : 
    2639                 : #if ECWSDK_VERSION >= 40
    2640                 :     pszOpt = CPLGetConfigOption( "ECW_AUTOGEN_J2I", NULL );
    2641                 :     if( pszOpt )
    2642                 :         NCSecwSetConfig( NCSCFG_JP2_AUTOGEN_J2I, 
    2643                 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    2644                 : 
    2645                 :     pszOpt = CPLGetConfigOption( "ECW_OPTIMIZE_USE_NEAREST_NEIGHBOUR", NULL );
    2646                 :     if( pszOpt )
    2647                 :         NCSecwSetConfig( NCSCFG_OPTIMIZE_USE_NEAREST_NEIGHBOUR, 
    2648                 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    2649                 : 
    2650                 : 
    2651                 :     pszOpt = CPLGetConfigOption( "ECW_RESILIENT_DECODING", NULL );
    2652                 :     if( pszOpt )
    2653                 :         NCSecwSetConfig( NCSCFG_RESILIENT_DECODING, 
    2654                 :                          (BOOLEAN) CSLTestBoolean( pszOpt ) );
    2655                 : #endif
    2656                 : }
    2657                 : 
    2658                 : /************************************************************************/
    2659                 : /*                         GDALDeregister_ECW()                         */
    2660                 : /************************************************************************/
    2661                 : 
    2662             550 : void GDALDeregister_ECW( GDALDriver * )
    2663                 : 
    2664                 : {
    2665                 :     /* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
    2666                 :     /* Not worth it */
    2667                 : #ifdef notdef
    2668                 :     if( bNCSInitialized )
    2669                 :     {
    2670                 :         bNCSInitialized = FALSE;
    2671                 : #ifndef WIN32
    2672                 :         NCSecwShutdown();
    2673                 : #endif
    2674                 :     }
    2675                 : 
    2676                 :     if( hECWDatasetMutex != NULL )
    2677                 :     {
    2678                 :         CPLDestroyMutex( hECWDatasetMutex );
    2679                 :         hECWDatasetMutex = NULL;
    2680                 :     }
    2681                 : #endif
    2682             550 : }
    2683                 : 
    2684                 : /************************************************************************/
    2685                 : /*                          GDALRegister_ECW()                        */
    2686                 : /************************************************************************/
    2687                 : 
    2688                 : /* Needed for v4.3 and v5.0 */
    2689                 : #if !defined(NCS_ECWSDK_VERSION_STRING) && defined(NCS_ECWJP2_VERSION_STRING)
    2690                 : #define NCS_ECWSDK_VERSION_STRING NCS_ECWJP2_VERSION_STRING
    2691                 : #endif
    2692                 : 
    2693             610 : void GDALRegister_ECW()
    2694                 : 
    2695                 : {
    2696                 : #ifdef FRMT_ecw 
    2697                 :     GDALDriver  *poDriver;
    2698                 : 
    2699             610 :     if (! GDAL_CHECK_VERSION("ECW driver"))
    2700               0 :         return;
    2701                 : 
    2702             610 :     if( GDALGetDriverByName( "ECW" ) == NULL )
    2703                 :     {
    2704             588 :         poDriver = new GDALDriver();
    2705                 :         
    2706             588 :         poDriver->SetDescription( "ECW" );
    2707                 : 
    2708             588 :         CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
    2709                 : 
    2710                 : #ifdef NCS_ECWSDK_VERSION_STRING
    2711                 :         osLongName += NCS_ECWSDK_VERSION_STRING;
    2712                 : #else
    2713             588 :         osLongName += "3.x";
    2714                 : #endif        
    2715             588 :         osLongName += ")";
    2716                 : 
    2717             588 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
    2718                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2719             588 :                                    "frmt_ecw.html" );
    2720             588 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
    2721                 :         
    2722             588 :         poDriver->pfnIdentify = ECWDataset::IdentifyECW;
    2723             588 :         poDriver->pfnOpen = ECWDataset::OpenECW;
    2724             588 :         poDriver->pfnUnloadDriver = GDALDeregister_ECW;
    2725                 : #ifdef HAVE_COMPRESS
    2726                 : // The create method seems not to work properly.
    2727                 : //        poDriver->pfnCreate = ECWCreateECW;  
    2728             588 :         poDriver->pfnCreateCopy = ECWCreateCopyECW;
    2729                 : #if ECWSDK_VERSION >= 50
    2730                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2731                 :                                    "Byte UInt16" );
    2732                 : #else 
    2733                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2734             588 :                                    "Byte" );
    2735                 : #endif
    2736                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    2737                 : "<CreationOptionList>"
    2738                 : "   <Option name='TARGET' type='float' description='Compression Percentage' />"
    2739                 : "   <Option name='PROJ' type='string' description='ECW Projection Name'/>"
    2740                 : "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
    2741                 : 
    2742                 : #if ECWSDK_VERSION < 40
    2743                 : "   <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
    2744                 : #else
    2745                 : "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
    2746                 : "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
    2747                 : #endif
    2748                 : 
    2749                 : #if ECWSDK_VERSION >= 50
    2750                 : "   <Option name='ECW_FORMAT_VERSION' type='integer' description='ECW format version (2 or 3).' default='2'/>"
    2751                 : #endif
    2752                 : 
    2753             588 : "</CreationOptionList>" );
    2754                 : #else
    2755                 :         /* In read-only mode, we support VirtualIO. This is not the case */
    2756                 :         /* for ECWCreateCopyECW() */
    2757                 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2758                 : #endif
    2759                 : 
    2760             588 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2761                 :     }
    2762                 : #endif /* def FRMT_ecw */
    2763                 : }
    2764                 : 
    2765                 : /************************************************************************/
    2766                 : /*                      GDALRegister_ECW_JP2ECW()                       */
    2767                 : /*                                                                      */
    2768                 : /*      This function exists so that when built as a plugin, there      */
    2769                 : /*      is a function that will register both drivers.                  */
    2770                 : /************************************************************************/
    2771                 : 
    2772               0 : void GDALRegister_ECW_JP2ECW()
    2773                 : 
    2774                 : {
    2775               0 :     GDALRegister_ECW();
    2776               0 :     GDALRegister_JP2ECW();
    2777               0 : }
    2778                 : 
    2779                 : /************************************************************************/
    2780                 : /*                     ECWDatasetOpenJPEG2000()                         */
    2781                 : /************************************************************************/
    2782              17 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
    2783                 : {
    2784              17 :     return ECWDataset::OpenJPEG2000(poOpenInfo);
    2785                 : }
    2786                 : 
    2787                 : /************************************************************************/
    2788                 : /*                        GDALRegister_JP2ECW()                         */
    2789                 : /************************************************************************/
    2790             610 : void GDALRegister_JP2ECW()
    2791                 : 
    2792                 : {
    2793                 : #ifdef FRMT_ecw 
    2794                 :     GDALDriver  *poDriver;
    2795                 : 
    2796             610 :     if (! GDAL_CHECK_VERSION("JP2ECW driver"))
    2797               0 :         return;
    2798                 : 
    2799             610 :     if( GDALGetDriverByName( "JP2ECW" ) == NULL )
    2800                 :     {
    2801             588 :         poDriver = new GDALDriver();
    2802                 :         
    2803             588 :         poDriver->SetDescription( "JP2ECW" );
    2804                 : 
    2805             588 :         CPLString osLongName = "ERDAS JPEG2000 (SDK ";
    2806                 : 
    2807                 : #ifdef NCS_ECWSDK_VERSION_STRING
    2808                 :         osLongName += NCS_ECWSDK_VERSION_STRING;
    2809                 : #else
    2810             588 :         osLongName += "3.x";
    2811                 : #endif        
    2812             588 :         osLongName += ")";
    2813                 : 
    2814             588 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
    2815                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2816             588 :                                    "frmt_jp2ecw.html" );
    2817             588 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
    2818             588 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2819                 :         
    2820             588 :         poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
    2821             588 :         poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
    2822                 : #ifdef HAVE_COMPRESS
    2823             588 :         poDriver->pfnCreate = ECWCreateJPEG2000;
    2824             588 :         poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
    2825                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2826             588 :                                    "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
    2827                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
    2828                 : "<CreationOptionList>"
    2829                 : "   <Option name='TARGET' type='float' description='Compression Percentage' />"
    2830                 : "   <Option name='PROJ' type='string' description='ECW Projection Name'/>"
    2831                 : "   <Option name='DATUM' type='string' description='ECW Datum Name' />"
    2832                 : "   <Option name='UNITS' type='string-select' description='ECW Projection Units'>"
    2833                 : "       <Value>METERS</Value>"
    2834                 : "       <Value>FEET</Value>"
    2835                 : "   </Option>"
    2836                 : 
    2837                 : #if ECWSDK_VERSION < 40
    2838                 : "   <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
    2839                 : #else
    2840                 : "   <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
    2841                 : "   <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
    2842                 : #endif
    2843                 : 
    2844                 : "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
    2845                 : "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
    2846                 : "   <Option name='PROFILE' type='string-select'>"
    2847                 : "       <Value>BASELINE_0</Value>"
    2848                 : "       <Value>BASELINE_1</Value>"
    2849                 : "       <Value>BASELINE_2</Value>"
    2850                 : "       <Value>NPJE</Value>"
    2851                 : "       <Value>EPJE</Value>"
    2852                 : "   </Option>"
    2853                 : "   <Option name='PROGRESSION' type='string-select'>"
    2854                 : "       <Value>LRCP</Value>"
    2855                 : "       <Value>RLCP</Value>"
    2856                 : "       <Value>RPCL</Value>"
    2857                 : "   </Option>"
    2858                 : "   <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
    2859                 : "   <Option name='LEVELS' type='int'/>"
    2860                 : "   <Option name='LAYERS' type='int'/>"
    2861                 : "   <Option name='PRECINCT_WIDTH' type='int'/>"
    2862                 : "   <Option name='PRECINCT_HEIGHT' type='int'/>"
    2863                 : "   <Option name='TILE_WIDTH' type='int'/>"
    2864                 : "   <Option name='TILE_HEIGHT' type='int'/>"
    2865                 : "   <Option name='INCLUDE_SOP' type='boolean'/>"
    2866                 : "   <Option name='INCLUDE_EPH' type='boolean'/>"
    2867                 : "   <Option name='DECOMPRESS_LAYERS' type='int'/>"
    2868                 : "   <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
    2869             588 : "</CreationOptionList>" );
    2870                 : #endif
    2871                 : 
    2872             588 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2873                 :     }
    2874                 : #endif /* def FRMT_ecw */
    2875                 : }

Generated by: LCOV version 1.7