LCOV - code coverage report
Current view: directory - frmts/wcs - wcsdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 755 342 45.3 %
Date: 2011-12-18 Functions: 34 21 61.8 %

       1                 : /******************************************************************************
       2                 :  * $Id: wcsdataset.cpp 22618 2011-06-29 20:02:57Z rouault $
       3                 :  *
       4                 :  * Project:  WCS Client Driver
       5                 :  * Purpose:  Implementation of Dataset and RasterBand classes for WCS.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2006, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_pam.h"
      31                 : #include "cpl_string.h"
      32                 : #include "cpl_minixml.h"
      33                 : #include "cpl_http.h"
      34                 : #include "ogr_spatialref.h"
      35                 : 
      36                 : CPL_CVSID("$Id: wcsdataset.cpp 22618 2011-06-29 20:02:57Z rouault $");
      37                 : 
      38                 : /************************************************************************/
      39                 : /* ==================================================================== */
      40                 : /*        WCSDataset        */
      41                 : /* ==================================================================== */
      42                 : /************************************************************************/
      43                 : 
      44                 : class WCSRasterBand;
      45                 : 
      46                 : class CPL_DLL WCSDataset : public GDALPamDataset
      47                 : {
      48                 :     friend class WCSRasterBand;
      49                 : 
      50                 :     int         bServiceDirty;
      51                 :     CPLXMLNode *psService;
      52                 : 
      53                 :     char       *apszCoverageOfferingMD[2];
      54                 : 
      55                 :     char      **papszSDSModifiers;
      56                 : 
      57                 :     int         nVersion;  // eg 100 for 1.0.0, 110 for 1.1.0
      58                 : 
      59                 :     CPLString   osCRS;
      60                 : 
      61                 :     char        *pszProjection;
      62                 :     double      adfGeoTransform[6];
      63                 : 
      64                 :     CPLString   osBandIdentifier;
      65                 : 
      66                 :     CPLString   osDefaultTime;
      67                 :     std::vector<CPLString> aosTimePositions;
      68                 : 
      69                 :     int         TestUseBlockIO( int, int, int, int, int, int );
      70                 :     CPLErr      DirectRasterIO( GDALRWFlag, int, int, int, int,
      71                 :                                 void *, int, int, GDALDataType,
      72                 :                                 int, int *, int, int, int );
      73                 :     CPLErr      GetCoverage( int nXOff, int nYOff, int nXSize, int nYSize,
      74                 :                              int nBufXSize, int nBufYSize, 
      75                 :                              int nBandCount, int *panBandList,
      76                 :                              CPLHTTPResult **ppsResult );
      77                 : 
      78                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
      79                 :                               void *, int, int, GDALDataType,
      80                 :                               int, int *, int, int, int );
      81                 : 
      82                 :     int   DescribeCoverage();
      83                 :     int         ExtractGridInfo100();
      84                 :     int         ExtractGridInfo();
      85                 :     int         EstablishRasterDetails();
      86                 : 
      87                 :     int         ProcessError( CPLHTTPResult *psResult );
      88                 :     GDALDataset *GDALOpenResult( CPLHTTPResult *psResult );
      89                 :     void        FlushMemoryResult();
      90                 :     CPLString   osResultFilename;
      91                 :     GByte      *pabySavedDataBuffer;
      92                 : 
      93                 :     char      **papszHttpOptions;
      94                 : 
      95                 :     int         nMaxCols;
      96                 :     int         nMaxRows;
      97                 :     
      98                 :   public:
      99                 :                 WCSDataset();
     100                 :                 ~WCSDataset();
     101                 : 
     102                 :     static GDALDataset *Open( GDALOpenInfo * );
     103                 :     static int Identify( GDALOpenInfo * );
     104                 : 
     105                 :     virtual CPLErr GetGeoTransform( double * );
     106                 :     virtual const char *GetProjectionRef(void);
     107                 :     virtual char **GetFileList(void);
     108                 : 
     109                 :     virtual char **GetMetadata( const char *pszDomain );
     110                 : };
     111                 : 
     112                 : /************************************************************************/
     113                 : /* ==================================================================== */
     114                 : /*                            WCSRasterBand                             */
     115                 : /* ==================================================================== */
     116                 : /************************************************************************/
     117                 : 
     118                 : class WCSRasterBand : public GDALPamRasterBand
     119                 : {
     120                 :     friend class WCSDataset;
     121                 : 
     122                 :     int            iOverview;
     123                 :     int            nResFactor;
     124                 : 
     125                 :     WCSDataset    *poODS;
     126                 : 
     127                 :     int            nOverviewCount;
     128                 :     WCSRasterBand **papoOverviews;
     129                 :     
     130                 :     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
     131                 :                               void *, int, int, GDALDataType,
     132                 :                               int, int );
     133                 : 
     134                 :   public:
     135                 : 
     136                 :                    WCSRasterBand( WCSDataset *, int nBand, int iOverview );
     137                 :                   ~WCSRasterBand();
     138                 : 
     139                 :     virtual double GetNoDataValue( int *pbSuccess = NULL );
     140                 : 
     141                 :     virtual int GetOverviewCount();
     142                 :     virtual GDALRasterBand *GetOverview(int);
     143                 : 
     144                 :     virtual CPLErr IReadBlock( int, int, void * );
     145                 : };
     146                 : 
     147                 : /************************************************************************/
     148                 : /*                           WCSRasterBand()                            */
     149                 : /************************************************************************/
     150                 : 
     151              12 : WCSRasterBand::WCSRasterBand( WCSDataset *poDS, int nBand, int iOverview )
     152                 : 
     153                 : {
     154              12 :     poODS = poDS;
     155              12 :     this->nBand = nBand;
     156                 : 
     157                 :     eDataType = GDALGetDataTypeByName( 
     158              12 :         CPLGetXMLValue( poDS->psService, "BandType", "Byte" ) );
     159                 : 
     160                 : /* -------------------------------------------------------------------- */
     161                 : /*      Establish resolution reduction for this overview level.         */
     162                 : /* -------------------------------------------------------------------- */
     163              12 :     this->iOverview = iOverview;
     164              12 :     nResFactor = 1 << (iOverview+1); // iOverview == -1 is base layer
     165                 : 
     166                 : /* -------------------------------------------------------------------- */
     167                 : /*      Establish block size.                                           */
     168                 : /* -------------------------------------------------------------------- */
     169              12 :     nRasterXSize = poDS->GetRasterXSize() / nResFactor;
     170              12 :     nRasterYSize = poDS->GetRasterYSize() / nResFactor;
     171                 :     
     172              12 :     nBlockXSize = atoi(CPLGetXMLValue( poDS->psService, "BlockXSize", "0" ) );
     173              12 :     nBlockYSize = atoi(CPLGetXMLValue( poDS->psService, "BlockYSize", "0" ) );
     174                 : 
     175              12 :     if( nBlockXSize < 1 )
     176                 :     {
     177              12 :         if( nRasterXSize > 1800 )
     178               0 :             nBlockXSize = 1024;
     179                 :         else
     180              12 :             nBlockXSize = nRasterXSize;
     181                 :     }
     182                 :     
     183              12 :     if( nBlockYSize < 1 )
     184                 :     {
     185              12 :         if( nRasterYSize > 900 )
     186               0 :             nBlockYSize = 512;
     187                 :         else
     188              12 :             nBlockYSize = nRasterYSize;
     189                 :     }
     190                 : 
     191                 : /* -------------------------------------------------------------------- */
     192                 : /*      If this is the base layer, create the overview layers.          */
     193                 : /* -------------------------------------------------------------------- */
     194              12 :     if( iOverview == -1 )
     195                 :     {
     196                 :         int i;
     197                 : 
     198                 :         nOverviewCount = atoi(CPLGetXMLValue(poODS->psService,"OverviewCount",
     199               6 :                                              "-1"));
     200               6 :         if( nOverviewCount < 0 )
     201                 :         {
     202               6 :             for( nOverviewCount = 0; 
     203                 :                  (MAX(nRasterXSize,nRasterYSize) / (1 << nOverviewCount)) > 900;
     204                 :                  nOverviewCount++ ) {}
     205                 :         }
     206               0 :         else if( nOverviewCount > 30 )
     207                 :         {
     208                 :             /* There's no reason to have more than 30 overviews, because */
     209                 :             /* 2^(30+1) overflows a int32 */
     210               0 :             nOverviewCount = 30;
     211                 :         }
     212                 : 
     213                 :         papoOverviews = (WCSRasterBand **) 
     214               6 :             CPLCalloc( nOverviewCount, sizeof(void*) );
     215                 :         
     216              24 :         for( i = 0; i < nOverviewCount; i++ )
     217               6 :             papoOverviews[i] = new WCSRasterBand( poODS, nBand, i );
     218                 :     }
     219                 :     else
     220                 :     {
     221               6 :         nOverviewCount = 0;
     222               6 :         papoOverviews = NULL;
     223                 :     }
     224              12 : }
     225                 : 
     226                 : /************************************************************************/
     227                 : /*                           ~WCSRasterBand()                           */
     228                 : /************************************************************************/
     229                 : 
     230              12 : WCSRasterBand::~WCSRasterBand()
     231                 :     
     232                 : {
     233              12 :     FlushCache();
     234                 :     
     235              12 :     if( nOverviewCount > 0 )
     236                 :     {
     237                 :         int i;
     238                 :         
     239              12 :         for( i = 0; i < nOverviewCount; i++ )
     240               6 :             delete papoOverviews[i];
     241                 : 
     242               6 :         CPLFree( papoOverviews );
     243                 :     }
     244              12 : }
     245                 : 
     246                 : /************************************************************************/
     247                 : /*                             IReadBlock()                             */
     248                 : /************************************************************************/
     249                 : 
     250               1 : CPLErr WCSRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     251                 :                                   void * pImage )
     252                 : 
     253                 : {
     254                 :     CPLErr eErr;
     255               1 :     CPLHTTPResult *psResult = NULL;
     256                 : 
     257                 :     eErr = poODS->GetCoverage( nBlockXOff * nBlockXSize * nResFactor, 
     258                 :                                nBlockYOff * nBlockYSize * nResFactor,
     259                 :                                nBlockXSize * nResFactor, 
     260                 :                                nBlockYSize * nResFactor, 
     261                 :                                nBlockXSize, nBlockYSize, 
     262               1 :                                1, &nBand, &psResult );
     263               1 :     if( eErr != CE_None )
     264               0 :         return eErr;
     265                 : 
     266                 : /* -------------------------------------------------------------------- */
     267                 : /*      Try and open result as a dataseat.                               */
     268                 : /* -------------------------------------------------------------------- */
     269               1 :     GDALDataset *poTileDS = poODS->GDALOpenResult( psResult );
     270                 : 
     271               1 :     if( poTileDS == NULL )
     272               0 :         return CE_Failure;
     273                 : 
     274                 : /* -------------------------------------------------------------------- */
     275                 : /*      Verify configuration.                                           */
     276                 : /* -------------------------------------------------------------------- */
     277               1 :     if( poTileDS->GetRasterXSize() != nBlockXSize
     278                 :         || poTileDS->GetRasterYSize() != nBlockYSize )
     279                 :     {
     280                 :         CPLDebug( "WCS", "Got size=%dx%d instead of %dx%d.", 
     281                 :                   poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
     282               0 :                   nBlockXSize, nBlockYSize );
     283                 : 
     284                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     285                 :                   "Returned tile does not match expected configuration.\n"
     286                 :                   "Got %dx%d instead of %dx%d.", 
     287                 :                   poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
     288               0 :                   nBlockXSize, nBlockYSize );
     289               0 :         delete poTileDS;
     290               0 :         return CE_Failure;
     291                 :     }
     292                 : 
     293               1 :     if( (strlen(poODS->osBandIdentifier) && poTileDS->GetRasterCount() != 1)
     294                 :         || (!strlen(poODS->osBandIdentifier) 
     295                 :             && poTileDS->GetRasterCount() != poODS->GetRasterCount()) )
     296                 :     {
     297                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     298               0 :                   "Returned tile does not match expected band configuration.");
     299               0 :         delete poTileDS;
     300               0 :         return CE_Failure;
     301                 :     }
     302                 : 
     303                 : /* -------------------------------------------------------------------- */
     304                 : /*      Process all bands of memory result, copying into pBuffer, or    */
     305                 : /*      pushing into cache for other bands.                             */
     306                 : /* -------------------------------------------------------------------- */
     307                 :     int iBand;
     308               1 :     eErr = CE_None;
     309                 :     
     310               4 :     for( iBand = 0; 
     311                 :          iBand < poTileDS->GetRasterCount() && eErr == CE_None; 
     312                 :          iBand++ )
     313                 :     {
     314               3 :         GDALRasterBand *poTileBand = poTileDS->GetRasterBand( iBand+1 );
     315                 : 
     316               3 :         if( iBand+1 == GetBand() || strlen(poODS->osBandIdentifier) )
     317                 :         {
     318                 :             eErr = poTileBand->RasterIO( GF_Read, 
     319                 :                                          0, 0, nBlockXSize, nBlockYSize, 
     320                 :                                          pImage, nBlockXSize, nBlockYSize, 
     321               1 :                                          eDataType, 0, 0 );
     322                 :         }
     323                 :         else
     324                 :         {
     325               2 :             GDALRasterBand *poTargBand = poODS->GetRasterBand( iBand+1 );
     326                 :             
     327               2 :             if( iOverview != -1 )
     328               0 :                 poTargBand = poTargBand->GetOverview( iOverview );
     329                 :             
     330                 :             GDALRasterBlock *poBlock = poTargBand->GetLockedBlockRef(
     331               2 :                 nBlockXOff, nBlockYOff, TRUE );
     332                 : 
     333               2 :             if( poBlock != NULL )
     334                 :             {
     335                 :                 eErr = poTileBand->RasterIO( GF_Read,
     336                 :                                             0, 0, nBlockXSize, nBlockYSize,
     337                 :                                             poBlock->GetDataRef(),
     338                 :                                             nBlockXSize, nBlockYSize,
     339               2 :                                             eDataType, 0, 0 );
     340               2 :                 poBlock->DropLock();
     341                 :             }
     342                 :             else
     343               0 :                 eErr = CE_Failure;
     344                 :         }
     345                 :     }
     346                 : 
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Cleanup                                                         */
     349                 : /* -------------------------------------------------------------------- */
     350               1 :     delete poTileDS;
     351                 :     
     352               1 :     poODS->FlushMemoryResult();
     353                 : 
     354               1 :     return eErr;
     355                 : }
     356                 : 
     357                 : /************************************************************************/
     358                 : /*                             IRasterIO()                              */
     359                 : /************************************************************************/
     360                 : 
     361             598 : CPLErr WCSRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     362                 :                                  int nXOff, int nYOff, int nXSize, int nYSize,
     363                 :                                  void * pData, int nBufXSize, int nBufYSize,
     364                 :                                  GDALDataType eBufType,
     365                 :                                  int nPixelSpace, int nLineSpace )
     366                 :     
     367                 : {
     368             598 :     if( (poODS->nMaxCols > 0 && poODS->nMaxCols < nBufXSize)
     369                 :         ||  (poODS->nMaxRows > 0 && poODS->nMaxRows < nBufYSize) )
     370               0 :         return CE_Failure;
     371                 : 
     372             598 :     if( poODS->TestUseBlockIO( nXOff, nYOff, nXSize, nYSize,
     373                 :                                nBufXSize,nBufYSize ) )
     374                 :         return GDALPamRasterBand::IRasterIO( 
     375                 :             eRWFlag, nXOff, nYOff, nXSize, nYSize,
     376                 :             pData, nBufXSize, nBufYSize, eBufType, 
     377             598 :             nPixelSpace, nLineSpace );
     378                 :     else
     379                 :         return poODS->DirectRasterIO( 
     380                 :             eRWFlag, 
     381                 :             nXOff * nResFactor, nYOff * nResFactor, 
     382                 :             nXSize * nResFactor, nYSize * nResFactor,
     383                 :             pData, nBufXSize, nBufYSize, eBufType, 
     384               0 :             1, &nBand, nPixelSpace, nLineSpace, 0 );
     385                 : }
     386                 : 
     387                 : /************************************************************************/
     388                 : /*                           GetNoDataValue()                           */
     389                 : /************************************************************************/
     390                 : 
     391               0 : double WCSRasterBand::GetNoDataValue( int *pbSuccess )
     392                 : 
     393                 : {
     394               0 :     const char *pszSV = CPLGetXMLValue( poODS->psService, "NoDataValue", NULL);
     395                 : 
     396               0 :     if( pszSV == NULL )
     397               0 :         return GDALPamRasterBand::GetNoDataValue( pbSuccess );
     398                 :     else
     399                 :     {
     400               0 :         if( pbSuccess )
     401               0 :             *pbSuccess = TRUE;
     402               0 :         return atof(pszSV);
     403                 :     }
     404                 : }
     405                 : 
     406                 : /************************************************************************/
     407                 : /*                          GetOverviewCount()                          */
     408                 : /************************************************************************/
     409                 : 
     410               1 : int WCSRasterBand::GetOverviewCount() 
     411                 :     
     412                 : {
     413               1 :     return nOverviewCount;
     414                 : }
     415                 : 
     416                 : /************************************************************************/
     417                 : /*                            GetOverview()                             */
     418                 : /************************************************************************/
     419                 : 
     420               0 : GDALRasterBand *WCSRasterBand::GetOverview( int iOverview )
     421                 : 
     422                 : {
     423               0 :     if( iOverview < 0 || iOverview >= nOverviewCount )
     424               0 :         return NULL;
     425                 :     else
     426               0 :         return papoOverviews[iOverview];
     427                 : }
     428                 : 
     429                 : /************************************************************************/
     430                 : /* ==================================================================== */
     431                 : /*                            WCSDataset                                */
     432                 : /* ==================================================================== */
     433                 : /************************************************************************/
     434                 : 
     435                 : 
     436                 : /************************************************************************/
     437                 : /*                             WCSDataset()                             */
     438                 : /************************************************************************/
     439                 : 
     440               2 : WCSDataset::WCSDataset()
     441                 : 
     442                 : {
     443               2 :     psService = NULL;
     444               2 :     bServiceDirty = FALSE;
     445               2 :     pszProjection = NULL;
     446                 :     
     447               2 :     adfGeoTransform[0] = 0.0;
     448               2 :     adfGeoTransform[1] = 1.0;
     449               2 :     adfGeoTransform[2] = 0.0;
     450               2 :     adfGeoTransform[3] = 0.0;
     451               2 :     adfGeoTransform[4] = 0.0;
     452               2 :     adfGeoTransform[5] = 1.0;
     453                 : 
     454               2 :     pabySavedDataBuffer = NULL;
     455               2 :     papszHttpOptions = NULL;
     456                 : 
     457               2 :     nMaxCols = -1;
     458               2 :     nMaxRows = -1;
     459                 : 
     460               2 :     apszCoverageOfferingMD[0] = NULL;
     461               2 :     apszCoverageOfferingMD[1] = NULL;
     462                 : 
     463               2 :     papszSDSModifiers = NULL;
     464               2 : }
     465                 : 
     466                 : /************************************************************************/
     467                 : /*                            ~WCSDataset()                             */
     468                 : /************************************************************************/
     469                 : 
     470               2 : WCSDataset::~WCSDataset()
     471                 : 
     472                 : {
     473                 :     // perhaps this should be moved into a FlushCache() method.
     474               2 :     if( bServiceDirty && !EQUALN(GetDescription(),"<WCS_GDAL>",10) )
     475                 :     {
     476               1 :         CPLSerializeXMLTreeToFile( psService, GetDescription() );
     477               1 :         bServiceDirty = FALSE;
     478                 :     }
     479                 : 
     480               2 :     CPLDestroyXMLNode( psService );
     481                 : 
     482               2 :     CPLFree( pszProjection );
     483               2 :     pszProjection = NULL;
     484                 : 
     485               2 :     CSLDestroy( papszHttpOptions );
     486               2 :     CSLDestroy( papszSDSModifiers );
     487                 : 
     488               2 :     CPLFree( apszCoverageOfferingMD[0] );
     489                 : 
     490               2 :     FlushMemoryResult();
     491               2 : }
     492                 : 
     493                 : /************************************************************************/
     494                 : /*                           TestUseBlockIO()                           */
     495                 : /*                                                                      */
     496                 : /*      Check whether we should use blocked IO (true) or direct io      */
     497                 : /*      (FALSE) for a given request configuration and environment.      */
     498                 : /************************************************************************/
     499                 : 
     500             598 : int WCSDataset::TestUseBlockIO( int nXOff, int nYOff, int nXSize, int nYSize,
     501                 :                                 int nBufXSize, int nBufYSize )
     502                 : 
     503                 : {
     504             598 :     int bUseBlockedIO = bForceCachedIO;
     505                 : 
     506             598 :     if( nYSize == 1 || nXSize * ((double) nYSize) < 100.0 )
     507             598 :         bUseBlockedIO = TRUE;
     508                 : 
     509             598 :     if( nBufYSize == 1 || nBufXSize * ((double) nBufYSize) < 100.0 )
     510             598 :         bUseBlockedIO = TRUE;
     511                 : 
     512             598 :     if( bUseBlockedIO
     513                 :         && CSLTestBoolean( CPLGetConfigOption( "GDAL_ONE_BIG_READ", "NO") ) )
     514               0 :         bUseBlockedIO = FALSE;
     515                 : 
     516             598 :     return bUseBlockedIO;
     517                 : }
     518                 : 
     519                 : /************************************************************************/
     520                 : /*                             IRasterIO()                              */
     521                 : /************************************************************************/
     522                 : 
     523               0 : CPLErr WCSDataset::IRasterIO( GDALRWFlag eRWFlag,
     524                 :                               int nXOff, int nYOff, int nXSize, int nYSize,
     525                 :                               void * pData, int nBufXSize, int nBufYSize,
     526                 :                               GDALDataType eBufType, 
     527                 :                               int nBandCount, int *panBandMap,
     528                 :                               int nPixelSpace, int nLineSpace, int nBandSpace)
     529                 : 
     530                 : {
     531               0 :     if( (nMaxCols > 0 && nMaxCols < nBufXSize)
     532                 :         ||  (nMaxRows > 0 && nMaxRows < nBufYSize) )
     533               0 :         return CE_Failure;
     534                 : 
     535                 : /* -------------------------------------------------------------------- */
     536                 : /*      We need various criteria to skip out to block based methods.    */
     537                 : /* -------------------------------------------------------------------- */
     538               0 :     if( TestUseBlockIO( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize ) )
     539                 :         return GDALPamDataset::IRasterIO( 
     540                 :             eRWFlag, nXOff, nYOff, nXSize, nYSize,
     541                 :             pData, nBufXSize, nBufYSize, eBufType, 
     542               0 :             nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
     543                 :     else
     544                 :         return DirectRasterIO( 
     545                 :             eRWFlag, nXOff, nYOff, nXSize, nYSize,
     546                 :             pData, nBufXSize, nBufYSize, eBufType, 
     547               0 :             nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
     548                 : }
     549                 : 
     550                 : /************************************************************************/
     551                 : /*                           DirectRasterIO()                           */
     552                 : /*                                                                      */
     553                 : /*      Make exactly one request to the server for this data.           */
     554                 : /************************************************************************/
     555                 : 
     556                 : CPLErr 
     557               0 : WCSDataset::DirectRasterIO( GDALRWFlag eRWFlag,
     558                 :                             int nXOff, int nYOff, int nXSize, int nYSize,
     559                 :                             void * pData, int nBufXSize, int nBufYSize,
     560                 :                             GDALDataType eBufType, 
     561                 :                             int nBandCount, int *panBandMap,
     562                 :                             int nPixelSpace, int nLineSpace, int nBandSpace)
     563                 : 
     564                 : {
     565                 :     CPLDebug( "WCS", "DirectRasterIO(%d,%d,%d,%d) -> (%d,%d) (%d bands)\n", 
     566                 :               nXOff, nYOff, nXSize, nYSize, 
     567               0 :               nBufXSize, nBufYSize, nBandCount );
     568                 : 
     569                 : /* -------------------------------------------------------------------- */
     570                 : /*      Get the coverage.                                               */
     571                 : /* -------------------------------------------------------------------- */
     572               0 :     CPLHTTPResult *psResult = NULL;
     573                 :     CPLErr eErr = 
     574                 :         GetCoverage( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, 
     575               0 :                      nBandCount, panBandMap, &psResult );
     576                 : 
     577               0 :     if( eErr != CE_None )
     578               0 :         return eErr;
     579                 : 
     580                 : /* -------------------------------------------------------------------- */
     581                 : /*      Try and open result as a dataseat.                               */
     582                 : /* -------------------------------------------------------------------- */
     583               0 :     GDALDataset *poTileDS = GDALOpenResult( psResult );
     584                 : 
     585               0 :     if( poTileDS == NULL )
     586               0 :         return CE_Failure;
     587                 : 
     588                 : /* -------------------------------------------------------------------- */
     589                 : /*      Verify configuration.                                           */
     590                 : /* -------------------------------------------------------------------- */
     591               0 :     if( poTileDS->GetRasterXSize() != nBufXSize
     592                 :         || poTileDS->GetRasterYSize() != nBufYSize )
     593                 :     {
     594                 :         CPLDebug( "WCS", "Got size=%dx%d instead of %dx%d.", 
     595                 :                   poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
     596               0 :                   nBufXSize, nBufYSize );
     597                 : 
     598                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     599                 :                   "Returned tile does not match expected configuration.\n"
     600                 :                   "Got %dx%d instead of %dx%d.", 
     601                 :                   poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
     602               0 :                   nBufXSize, nBufYSize );
     603               0 :         delete poTileDS;
     604               0 :         return CE_Failure;
     605                 :     }
     606                 : 
     607               0 :     if( (strlen(osBandIdentifier) && poTileDS->GetRasterCount() != nBandCount)
     608                 :         || (!strlen(osBandIdentifier) && poTileDS->GetRasterCount() != 
     609                 :             GetRasterCount() ) )
     610                 :     {
     611                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     612               0 :                   "Returned tile does not match expected band count." );
     613               0 :         delete poTileDS;
     614               0 :         return CE_Failure;
     615                 :     }
     616                 :     
     617                 : /* -------------------------------------------------------------------- */
     618                 : /*      Pull requested bands from the downloaded dataset.               */
     619                 : /* -------------------------------------------------------------------- */
     620                 :     int iBand;
     621                 : 
     622               0 :     eErr = CE_None;
     623                 :     
     624               0 :     for( iBand = 0; 
     625                 :          iBand < nBandCount && eErr == CE_None; 
     626                 :          iBand++ )
     627                 :     {
     628                 :         GDALRasterBand *poTileBand;
     629                 : 
     630               0 :         if( strlen(osBandIdentifier) )
     631               0 :             poTileBand = poTileDS->GetRasterBand( iBand + 1 );
     632                 :         else
     633               0 :             poTileBand = poTileDS->GetRasterBand( panBandMap[iBand] );
     634                 : 
     635                 :         eErr = poTileBand->RasterIO( GF_Read, 
     636                 :                                      0, 0, nBufXSize, nBufYSize,
     637                 :                                      ((GByte *) pData) + 
     638                 :                                      iBand * nBandSpace, nBufXSize, nBufYSize, 
     639               0 :                                      eBufType, nPixelSpace, nLineSpace );
     640                 :     }
     641                 :     
     642                 : /* -------------------------------------------------------------------- */
     643                 : /*      Cleanup                                                         */
     644                 : /* -------------------------------------------------------------------- */
     645               0 :     delete poTileDS;
     646                 :     
     647               0 :     FlushMemoryResult();
     648                 : 
     649               0 :     return eErr;
     650                 : }
     651                 : 
     652                 : /************************************************************************/
     653                 : /*                            GetCoverage()                             */
     654                 : /*                                                                      */
     655                 : /*      Issue the appropriate version of request for a given window,    */
     656                 : /*      buffer size and band list.                                      */
     657                 : /************************************************************************/
     658                 : 
     659               3 : CPLErr WCSDataset::GetCoverage( int nXOff, int nYOff, int nXSize, int nYSize,
     660                 :                                 int nBufXSize, int nBufYSize, 
     661                 :                                 int nBandCount, int *panBandList,
     662                 :                                 CPLHTTPResult **ppsResult )
     663                 : 
     664                 : {
     665               3 :     CPLLocaleC oLocaleEnforcer;
     666                 : 
     667                 : /* -------------------------------------------------------------------- */
     668                 : /*      Figure out the georeferenced extents.                           */
     669                 : /* -------------------------------------------------------------------- */
     670                 :     double dfMinX, dfMaxX, dfMinY, dfMaxY;
     671                 :     
     672                 :     // WCS 1.0 extents are the outer edges of outer pixels.
     673               3 :     dfMinX = adfGeoTransform[0] + 
     674               3 :         (nXOff) * adfGeoTransform[1];
     675               3 :     dfMaxX = adfGeoTransform[0] + 
     676               3 :         (nXOff + nXSize) * adfGeoTransform[1];
     677               3 :     dfMaxY = adfGeoTransform[3] + 
     678               3 :         (nYOff) * adfGeoTransform[5];
     679               3 :     dfMinY = adfGeoTransform[3] + 
     680               3 :         (nYOff + nYSize) * adfGeoTransform[5];
     681                 : 
     682                 : /* -------------------------------------------------------------------- */
     683                 : /*      Build band list if we have the band identifier.                 */
     684                 : /* -------------------------------------------------------------------- */
     685               3 :     CPLString osBandList;
     686               3 :     int       bSelectingBands = FALSE;
     687                 :     
     688               3 :     if( strlen(osBandIdentifier) && nBandCount > 0 )
     689                 :     {
     690                 :         int iBand;
     691                 : 
     692               0 :         for( iBand = 0; iBand < nBandCount; iBand++ )
     693                 :         {
     694               0 :             if( iBand > 0 )
     695               0 :                 osBandList += ",";
     696               0 :             osBandList += CPLString().Printf( "%d", panBandList[iBand] );
     697                 :         }
     698                 : 
     699               0 :         bSelectingBands = TRUE;
     700                 :     }
     701                 : 
     702                 : /* -------------------------------------------------------------------- */
     703                 : /*      URL encode strings that could have questionable characters.     */
     704                 : /* -------------------------------------------------------------------- */
     705               3 :     CPLString osCoverage, osFormat;
     706                 :     char *pszEncoded; 
     707                 : 
     708               3 :     osCoverage = CPLGetXMLValue( psService, "CoverageName", "" );
     709                 : 
     710               3 :     pszEncoded = CPLEscapeString( osCoverage, -1, CPLES_URL );
     711               3 :     osCoverage = pszEncoded;
     712               3 :     CPLFree( pszEncoded );
     713                 :     
     714               3 :     osFormat = CPLGetXMLValue( psService, "PreferredFormat", "" );
     715                 : 
     716               3 :     pszEncoded = CPLEscapeString( osFormat, -1, CPLES_URL );
     717               3 :     osFormat = pszEncoded;
     718               3 :     CPLFree( pszEncoded );
     719                 :     
     720                 : /* -------------------------------------------------------------------- */
     721                 : /*      Do we have a time we want to use?                               */
     722                 : /* -------------------------------------------------------------------- */
     723               3 :     CPLString osTime;
     724                 : 
     725               3 :     osTime = CSLFetchNameValueDef( papszSDSModifiers, "time", osDefaultTime );
     726                 :     
     727                 : /* -------------------------------------------------------------------- */
     728                 : /*      Construct a "simple" GetCoverage request (WCS 1.0).   */
     729                 : /* -------------------------------------------------------------------- */
     730               3 :     CPLString osRequest;
     731                 : 
     732               3 :     if( nVersion == 100 )
     733                 :     {
     734                 :         osRequest.Printf( 
     735                 :             "%sSERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&COVERAGE=%s"
     736                 :             "&FORMAT=%s&BBOX=%.15g,%.15g,%.15g,%.15g&WIDTH=%d&HEIGHT=%d&CRS=%s%s",
     737                 :             CPLGetXMLValue( psService, "ServiceURL", "" ),
     738                 :             osCoverage.c_str(),
     739                 :             osFormat.c_str(),
     740                 :             dfMinX, dfMinY, dfMaxX, dfMaxY,
     741                 :             nBufXSize, nBufYSize, 
     742                 :             osCRS.c_str(),
     743               3 :             CPLGetXMLValue( psService, "GetCoverageExtra", "" ) );
     744                 :  
     745               3 :         if( CPLGetXMLValue( psService, "Resample", NULL ) )
     746                 :         {
     747               0 :             osRequest += "&INTERPOLATION=";
     748               0 :             osRequest += CPLGetXMLValue( psService, "Resample", "" );
     749                 :         }
     750                 : 
     751               3 :         if( osTime != "" )
     752                 :         {
     753               0 :             osRequest += "&time=";
     754               0 :             osRequest += osTime;
     755                 :         }
     756                 : 
     757               3 :         if( bSelectingBands )
     758                 :         {
     759                 :             osRequest += CPLString().Printf( "&%s=%s", 
     760                 :                                              osBandIdentifier.c_str(),
     761               0 :                                              osBandList.c_str() );
     762                 :         }
     763                 :     }
     764                 : 
     765                 : /* -------------------------------------------------------------------- */
     766                 : /*      Construct a "simple" GetCoverage request (WCS 1.1+).            */
     767                 : /* -------------------------------------------------------------------- */
     768                 :     else
     769                 :     {
     770               0 :         CPLString osRangeSubset;
     771                 : 
     772                 :         osRangeSubset.Printf("&RangeSubset=%s", 
     773               0 :                              CPLGetXMLValue(psService,"FieldName",""));
     774                 :         
     775               0 :         if( CPLGetXMLValue( psService, "Resample", NULL ) )
     776                 :         {
     777               0 :             osRangeSubset += ":";
     778               0 :             osRangeSubset += CPLGetXMLValue( psService, "Resample", "");
     779                 :         }
     780                 : 
     781               0 :         if( bSelectingBands )
     782                 :         {
     783                 :             osRangeSubset += 
     784                 :                 CPLString().Printf( "[%s[%s]]",
     785                 :                                     osBandIdentifier.c_str(), 
     786               0 :                                     osBandList.c_str() );
     787                 :         }
     788                 : 
     789                 :         // WCS 1.1 extents are centers of outer pixels.
     790               0 :         dfMaxX -= adfGeoTransform[1] * 0.5;
     791               0 :         dfMinX += adfGeoTransform[1] * 0.5;
     792               0 :         dfMinY -= adfGeoTransform[5] * 0.5;
     793               0 :         dfMaxY += adfGeoTransform[5] * 0.5;
     794                 : 
     795                 :         // Carefully adjust bounds for pixel centered values at new 
     796                 :         // sampling density.
     797                 : 
     798               0 :         double dfXStep = adfGeoTransform[1];
     799               0 :         double dfYStep = adfGeoTransform[5];
     800                 : 
     801               0 :         if( nBufXSize != nXSize || nBufYSize != nYSize )
     802                 :         {
     803               0 :             dfXStep = (nXSize/(double)nBufXSize) * adfGeoTransform[1];
     804               0 :             dfYStep = (nYSize/(double)nBufYSize) * adfGeoTransform[5];
     805                 :             
     806               0 :             dfMinX  = nXOff * adfGeoTransform[1] + adfGeoTransform[0] 
     807               0 :                     + dfXStep * 0.5;
     808               0 :             dfMaxX  = dfMinX + (nBufXSize - 1) * dfXStep;
     809                 : 
     810               0 :             dfMaxY  = nYOff * adfGeoTransform[5] + adfGeoTransform[3] 
     811               0 :                     + dfYStep * 0.5;
     812               0 :             dfMinY  = dfMaxY + (nBufYSize - 1) * dfYStep;
     813                 :         }
     814                 : 
     815                 :         osRequest.Printf( 
     816                 :             "%sSERVICE=WCS&VERSION=%s&REQUEST=GetCoverage&IDENTIFIER=%s"
     817                 :             "&FORMAT=%s&BOUNDINGBOX=%.15g,%.15g,%.15g,%.15g,%s%s%s",
     818                 :             CPLGetXMLValue( psService, "ServiceURL", "" ),
     819                 :             CPLGetXMLValue( psService, "Version", "" ),
     820                 :             osCoverage.c_str(),
     821                 :             osFormat.c_str(),
     822                 :             dfMinX, dfMinY, dfMaxX, dfMaxY,
     823                 :             osCRS.c_str(),
     824                 :             osRangeSubset.c_str(),
     825               0 :             CPLGetXMLValue( psService, "GetCoverageExtra", "" ) );
     826                 : 
     827               0 :         if( nBufXSize != nXSize || nBufYSize != nYSize )
     828                 :         {
     829                 :             osRequest += CPLString().Printf( 
     830                 :                 "&GridBaseCRS=%s"
     831                 :                 "&GridCS=%s"
     832                 :                 "&GridType=urn:ogc:def:method:WCS:1.1:2dGridIn2dCrs"
     833                 :                 "&GridOrigin=%.15g,%.15g"
     834                 :                 "&GridOffsets=%.15g,%.15g",
     835                 :                 osCRS.c_str(), 
     836                 :                 osCRS.c_str(), 
     837                 :                 dfMinX, dfMaxY,
     838               0 :                 dfXStep, dfYStep );
     839               0 :         }
     840                 :     }
     841                 : 
     842                 : /* -------------------------------------------------------------------- */
     843                 : /*      Fetch the result.                                               */
     844                 : /* -------------------------------------------------------------------- */
     845               3 :     CPLErrorReset();
     846                 : 
     847               3 :     *ppsResult = CPLHTTPFetch( osRequest, papszHttpOptions );
     848                 : 
     849               3 :     if( ProcessError( *ppsResult ) )
     850               0 :         return CE_Failure;
     851                 :     else
     852               3 :         return CE_None;
     853                 : }
     854                 : 
     855                 : /************************************************************************/
     856                 : /*                          DescribeCoverage()                          */
     857                 : /*                                                                      */
     858                 : /*      Fetch the DescribeCoverage result and attach it to the          */
     859                 : /*      service description.                                            */
     860                 : /************************************************************************/
     861                 : 
     862               2 : int WCSDataset::DescribeCoverage()
     863                 : 
     864                 : {
     865               2 :     CPLString osRequest;
     866                 : 
     867                 : /* -------------------------------------------------------------------- */
     868                 : /*      Fetch coverage description for this coverage.                   */
     869                 : /* -------------------------------------------------------------------- */
     870               2 :     if( nVersion == 100 )
     871                 :         osRequest.Printf( 
     872                 :             "%sSERVICE=WCS&REQUEST=DescribeCoverage&VERSION=%s&COVERAGE=%s%s", 
     873                 :             CPLGetXMLValue( psService, "ServiceURL", "" ),
     874                 :             CPLGetXMLValue( psService, "Version", "1.0.0" ),
     875                 :             CPLGetXMLValue( psService, "CoverageName", "" ),
     876               2 :             CPLGetXMLValue( psService, "DescribeCoverageExtra", "" ) );
     877                 :     else
     878                 :         osRequest.Printf( 
     879                 :             "%sSERVICE=WCS&REQUEST=DescribeCoverage&VERSION=%s&IDENTIFIERS=%s%s&FORMAT=text/xml", 
     880                 :             CPLGetXMLValue( psService, "ServiceURL", "" ),
     881                 :             CPLGetXMLValue( psService, "Version", "1.0.0" ),
     882                 :             CPLGetXMLValue( psService, "CoverageName", "" ),
     883               0 :             CPLGetXMLValue( psService, "DescribeCoverageExtra", "" ) );
     884                 : 
     885               2 :     CPLErrorReset();
     886                 :     
     887               2 :     CPLHTTPResult *psResult = CPLHTTPFetch( osRequest, papszHttpOptions );
     888                 : 
     889               2 :     if( ProcessError( psResult ) )
     890               0 :         return FALSE;
     891                 :     
     892                 : /* -------------------------------------------------------------------- */
     893                 : /*      Parse result.                                                   */
     894                 : /* -------------------------------------------------------------------- */
     895               2 :     CPLXMLNode *psDC = CPLParseXMLString( (const char *) psResult->pabyData );
     896               2 :     CPLHTTPDestroyResult( psResult );
     897                 : 
     898               2 :     if( psDC == NULL )
     899               0 :         return FALSE;
     900                 : 
     901               2 :     CPLStripXMLNamespace( psDC, NULL, TRUE );
     902                 : 
     903                 : /* -------------------------------------------------------------------- */
     904                 : /*      Did we get a CoverageOffering?                                  */
     905                 : /* -------------------------------------------------------------------- */
     906                 :     CPLXMLNode *psCO;
     907                 : 
     908               2 :     if( nVersion == 100 )
     909               2 :         psCO = CPLGetXMLNode( psDC, "=CoverageDescription.CoverageOffering" );
     910                 :     else
     911               0 :         psCO =CPLGetXMLNode( psDC,"=CoverageDescriptions.CoverageDescription");
     912                 : 
     913               2 :     if( !psCO )
     914                 :     {
     915               0 :         CPLDestroyXMLNode( psDC );
     916                 : 
     917                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     918                 :                   "Failed to fetch a <CoverageOffering> back %s.", 
     919               0 :                   osRequest.c_str() );
     920               0 :         return FALSE;
     921                 :     }
     922                 : 
     923                 : /* -------------------------------------------------------------------- */
     924                 : /*      Duplicate the coverage offering, and insert into                */
     925                 : /* -------------------------------------------------------------------- */
     926               2 :     CPLXMLNode *psNext = psCO->psNext;
     927               2 :     psCO->psNext = NULL;
     928                 :     
     929               2 :     CPLAddXMLChild( psService, CPLCloneXMLTree( psCO ) );
     930               2 :     bServiceDirty = TRUE;
     931                 : 
     932               2 :     psCO->psNext = psNext;
     933                 : 
     934               2 :     CPLDestroyXMLNode( psDC );
     935               2 :     return TRUE;
     936                 : }
     937                 : 
     938                 : /************************************************************************/
     939                 : /*                         ExtractGridInfo100()                         */
     940                 : /*                                                                      */
     941                 : /*      Collect info about grid from describe coverage for WCS 1.0.0    */
     942                 : /*      and above.                                                      */
     943                 : /************************************************************************/
     944                 : 
     945               2 : int WCSDataset::ExtractGridInfo100()
     946                 : 
     947                 : {
     948               2 :     CPLXMLNode * psCO = CPLGetXMLNode( psService, "CoverageOffering" );
     949                 : 
     950               2 :     if( psCO == NULL )
     951               0 :         return FALSE;
     952                 : 
     953                 : /* -------------------------------------------------------------------- */
     954                 : /*      We need to strip off name spaces so it is easier to             */
     955                 : /*      searchfor plain gml names.                                      */
     956                 : /* -------------------------------------------------------------------- */
     957               2 :     CPLStripXMLNamespace( psCO, NULL, TRUE );
     958                 : 
     959                 : /* -------------------------------------------------------------------- */
     960                 : /*      Verify we have a Rectified Grid.                                */
     961                 : /* -------------------------------------------------------------------- */
     962                 :     CPLXMLNode *psRG = 
     963               2 :         CPLGetXMLNode( psCO, "domainSet.spatialDomain.RectifiedGrid" );
     964                 : 
     965               2 :     if( psRG == NULL )
     966                 :     {
     967                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     968                 :                   "Unable to find RectifiedGrid in CoverageOffering,\n"
     969               0 :                   "unable to process WCS Coverage." );
     970               0 :         return FALSE;
     971                 :     }
     972                 : 
     973                 : /* -------------------------------------------------------------------- */
     974                 : /*      Extract size, geotransform and coordinate system.               */
     975                 : /* -------------------------------------------------------------------- */
     976               2 :     if( GDALParseGMLCoverage( psRG, &nRasterXSize, &nRasterYSize, 
     977                 :                               adfGeoTransform, &pszProjection ) != CE_None )
     978               0 :         return FALSE;
     979                 : 
     980                 : /* -------------------------------------------------------------------- */
     981                 : /*      Fallback to nativeCRSs declaration.                             */
     982                 : /* -------------------------------------------------------------------- */
     983                 :     const char *pszNativeCRSs = 
     984               2 :         CPLGetXMLValue( psCO, "supportedCRSs.nativeCRSs", NULL );
     985                 : 
     986               2 :     if( pszNativeCRSs == NULL )
     987                 :         pszNativeCRSs = 
     988               2 :             CPLGetXMLValue( psCO, "supportedCRSs.requestResponseCRSs", NULL );
     989                 : 
     990               2 :     if( pszNativeCRSs == NULL )
     991                 :         pszNativeCRSs = 
     992               0 :             CPLGetXMLValue( psCO, "supportedCRSs.requestCRSs", NULL );
     993                 : 
     994               2 :     if( pszNativeCRSs == NULL )
     995                 :         pszNativeCRSs = 
     996               0 :             CPLGetXMLValue( psCO, "supportedCRSs.responseCRSs", NULL );
     997                 : 
     998               2 :     if( pszNativeCRSs != NULL  
     999                 :         && (pszProjection == NULL || strlen(pszProjection) == 0) )
    1000                 :     {
    1001               2 :         OGRSpatialReference oSRS;
    1002                 :         
    1003               2 :         if( oSRS.SetFromUserInput( pszNativeCRSs ) == OGRERR_NONE )
    1004                 :         {
    1005               2 :             CPLFree( pszProjection );
    1006               2 :             oSRS.exportToWkt( &pszProjection );
    1007                 :         }
    1008                 :         else
    1009                 :             CPLDebug( "WCS", 
    1010                 :                       "<nativeCRSs> element contents not parsable:\n%s", 
    1011               0 :                       pszNativeCRSs );
    1012                 :     }
    1013                 : 
    1014                 :     // We should try to use the services name for the CRS if possible.
    1015               2 :     if( pszNativeCRSs != NULL
    1016                 :         && ( EQUALN(pszNativeCRSs,"EPSG:",5)
    1017                 :              || EQUALN(pszNativeCRSs,"AUTO:",5)
    1018                 :              || EQUALN(pszNativeCRSs,"Image ",6)
    1019                 :              || EQUALN(pszNativeCRSs,"Engineering ",12)
    1020                 :              || EQUALN(pszNativeCRSs,"OGC:",4) ) )
    1021                 :     {
    1022               2 :         osCRS = pszNativeCRSs;
    1023                 :         
    1024               2 :         size_t nDivider = osCRS.find( " " );
    1025                 : 
    1026               2 :         if( nDivider != std::string::npos )
    1027               0 :             osCRS.resize( nDivider-1 );
    1028                 :     }
    1029                 : 
    1030                 : /* -------------------------------------------------------------------- */
    1031                 : /*      Do we have a coordinate system override?                        */
    1032                 : /* -------------------------------------------------------------------- */
    1033               2 :     const char *pszProjOverride = CPLGetXMLValue( psService, "SRS", NULL );
    1034                 :     
    1035               2 :     if( pszProjOverride )
    1036                 :     {
    1037               0 :         OGRSpatialReference oSRS;
    1038                 :         
    1039               0 :         if( oSRS.SetFromUserInput( pszProjOverride ) != OGRERR_NONE )
    1040                 :         {
    1041                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1042                 :                       "<SRS> element contents not parsable:\n%s", 
    1043               0 :                       pszProjOverride );
    1044               0 :             return FALSE;
    1045                 :         }
    1046                 : 
    1047               0 :         CPLFree( pszProjection );
    1048               0 :         oSRS.exportToWkt( &pszProjection );
    1049                 : 
    1050               0 :         if( EQUALN(pszProjOverride,"EPSG:",5)
    1051                 :             || EQUALN(pszProjOverride,"AUTO:",5)
    1052                 :             || EQUALN(pszProjOverride,"OGC:",4)
    1053                 :             || EQUALN(pszProjOverride,"Image ",6)
    1054                 :             || EQUALN(pszProjOverride,"Engineering ",12) )
    1055               0 :             osCRS = pszProjOverride;
    1056                 :     }
    1057                 : 
    1058                 : /* -------------------------------------------------------------------- */
    1059                 : /*      Build CRS name to use.                                          */
    1060                 : /* -------------------------------------------------------------------- */
    1061               2 :     OGRSpatialReference oSRS;
    1062                 :     const char *pszAuth;
    1063                 : 
    1064               2 :     if( pszProjection && strlen(pszProjection) > 0 && osCRS == "" )
    1065                 :     {
    1066               0 :         oSRS.SetFromUserInput( pszProjection );
    1067               0 :         pszAuth = oSRS.GetAuthorityName(NULL);
    1068                 :     
    1069               0 :         if( pszAuth != NULL && EQUAL(pszAuth,"EPSG") )
    1070                 :         {
    1071               0 :             pszAuth = oSRS.GetAuthorityCode(NULL);
    1072               0 :             if( pszAuth )
    1073                 :             {
    1074               0 :                 osCRS = "EPSG:";
    1075               0 :                 osCRS += pszAuth;
    1076                 :             }
    1077                 :             else
    1078                 :             {
    1079                 :                 CPLError( CE_Failure, CPLE_AppDefined,
    1080               0 :                           "Unable to define CRS to use." );
    1081               0 :                 return FALSE;
    1082                 :             }
    1083                 :         }
    1084                 :     }
    1085                 : 
    1086                 : /* -------------------------------------------------------------------- */
    1087                 : /*      Pick a format type if we don't already have one selected.       */
    1088                 : /*                                                                      */
    1089                 : /*      We will prefer anything that sounds like TIFF, otherwise        */
    1090                 : /*      falling back to the first supported format.  Should we          */
    1091                 : /*      consider preferring the nativeFormat if available?              */
    1092                 : /* -------------------------------------------------------------------- */
    1093               2 :     if( CPLGetXMLValue( psService, "PreferredFormat", NULL ) == NULL )
    1094                 :     {
    1095               2 :         CPLXMLNode *psSF = CPLGetXMLNode( psCO, "supportedFormats" );
    1096                 :         CPLXMLNode *psNode;
    1097               2 :         char **papszFormatList = NULL;
    1098               2 :         CPLString osPreferredFormat;
    1099                 :         int iFormat;
    1100                 : 
    1101               2 :         if( psSF == NULL )
    1102                 :         {
    1103                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1104                 :                       "No <PreferredFormat> tag in service definition file, and no\n"
    1105               0 :                       "<supportedFormats> in coverageOffering." );
    1106               0 :             return FALSE;
    1107                 :         }
    1108                 : 
    1109              12 :         for( psNode = psSF->psChild; psNode != NULL; psNode = psNode->psNext )
    1110                 :         {
    1111              10 :             if( psNode->eType == CXT_Element 
    1112                 :                 && EQUAL(psNode->pszValue,"formats") 
    1113                 :                 && psNode->psChild != NULL 
    1114                 :                 && psNode->psChild->eType == CXT_Text )
    1115                 :             {
    1116                 :                 // This check is looking for deprecated WCS 1.0 capabilities
    1117                 :                 // with multiple formats space delimited in a single <formats>
    1118                 :                 // element per GDAL ticket 1748 (done by MapServer 4.10 and
    1119                 :                 // earlier for instance). 
    1120               8 :                 if( papszFormatList == NULL
    1121                 :                     && psNode->psNext == NULL
    1122                 :                     && strstr(psNode->psChild->pszValue," ") != NULL
    1123                 :                     && strstr(psNode->psChild->pszValue,";") == NULL )
    1124                 :                 {
    1125                 :                     char **papszSubList = 
    1126               0 :                         CSLTokenizeString( psNode->psChild->pszValue );
    1127                 :                     papszFormatList = CSLInsertStrings( papszFormatList, 
    1128               0 :                                                         -1, papszSubList );
    1129               0 :                     CSLDestroy( papszSubList );
    1130                 :                 }
    1131                 :                 else
    1132                 :                 {
    1133                 :                     papszFormatList = CSLAddString( papszFormatList, 
    1134               8 :                                                     psNode->psChild->pszValue);
    1135                 :                 }
    1136                 :             }
    1137                 :         }
    1138                 :         
    1139               4 :         for( iFormat = 0; 
    1140               2 :              papszFormatList != NULL && papszFormatList[iFormat] != NULL;
    1141                 :              iFormat++ )
    1142                 :         {
    1143               2 :             if( strlen(osPreferredFormat) == 0 )
    1144               2 :                 osPreferredFormat = papszFormatList[iFormat];
    1145                 :             
    1146               2 :             if( strstr(papszFormatList[iFormat],"tiff") != NULL 
    1147                 :                     || strstr(papszFormatList[iFormat],"TIFF") != NULL
    1148                 :                     || strstr(papszFormatList[iFormat],"Tiff") != NULL )
    1149                 :             {
    1150               2 :                 osPreferredFormat = papszFormatList[iFormat];
    1151               2 :                 break;
    1152                 :             }
    1153                 :         }
    1154                 : 
    1155               2 :         CSLDestroy( papszFormatList );
    1156                 : 
    1157               2 :         if( strlen(osPreferredFormat) > 0 )
    1158                 :         {
    1159               2 :             bServiceDirty = TRUE;
    1160                 :             CPLCreateXMLElementAndValue( psService, "PreferredFormat", 
    1161               2 :                                          osPreferredFormat );
    1162               0 :         }
    1163                 :     }
    1164                 : 
    1165                 : /* -------------------------------------------------------------------- */
    1166                 : /*      Try to identify a nodata value.  For now we only support the    */
    1167                 : /*      singleValue mechanism.                                          */
    1168                 : /* -------------------------------------------------------------------- */
    1169               2 :     if( CPLGetXMLValue( psService, "NoDataValue", NULL ) == NULL )
    1170                 :     {
    1171               2 :         const char *pszSV = CPLGetXMLValue( psCO, "rangeSet.RangeSet.nullValues.singleValue", NULL );
    1172                 :         
    1173               2 :         if( pszSV != NULL && (atof(pszSV) != 0.0 || *pszSV == '0') )
    1174                 :         {
    1175               0 :             bServiceDirty = TRUE;
    1176                 :             CPLCreateXMLElementAndValue( psService, "NoDataValue", 
    1177               0 :                                          pszSV );
    1178                 :         }
    1179                 :     }
    1180                 : 
    1181                 : /* -------------------------------------------------------------------- */
    1182                 : /*      Do we have a Band range type.  For now we look for a fairly     */
    1183                 : /*      specific configuration.  The rangeset my have one axis named    */
    1184                 : /*      "Band", with a set of ascending numerical values.               */
    1185                 : /* -------------------------------------------------------------------- */
    1186               2 :     osBandIdentifier = CPLGetXMLValue( psService, "BandIdentifier", "" );
    1187                 :     CPLXMLNode * psAD = CPLGetXMLNode( psService, 
    1188               2 :       "CoverageOffering.rangeSet.RangeSet.axisDescription.AxisDescription" );
    1189                 :     CPLXMLNode *psValues;
    1190                 : 
    1191               2 :     if( strlen(osBandIdentifier) == 0
    1192                 :         && psAD != NULL 
    1193                 :         && (EQUAL(CPLGetXMLValue(psAD,"name",""),"Band") 
    1194                 :             || EQUAL(CPLGetXMLValue(psAD,"name",""),"Bands"))
    1195                 :         && ( (psValues = CPLGetXMLNode( psAD, "values" )) != NULL ) )
    1196                 :     {
    1197                 :         CPLXMLNode *psSV;
    1198                 :         int iBand;
    1199                 : 
    1200               2 :         osBandIdentifier = CPLGetXMLValue(psAD,"name","");
    1201                 : 
    1202               2 :         for( psSV = psValues->psChild, iBand = 1; 
    1203                 :              psSV != NULL; 
    1204                 :              psSV = psSV->psNext, iBand++ )
    1205                 :         {
    1206               2 :             if( psSV->eType != CXT_Element 
    1207                 :                 || !EQUAL(psSV->pszValue,"singleValue") 
    1208                 :                 || psSV->psChild == NULL
    1209                 :                 || psSV->psChild->eType != CXT_Text
    1210                 :                 || atoi(psSV->psChild->pszValue) != iBand )
    1211                 :             {
    1212               2 :                 osBandIdentifier = "";
    1213               2 :                 break;
    1214                 :             }
    1215                 :         }
    1216                 : 
    1217               2 :         if( strlen(osBandIdentifier) )
    1218                 :         {
    1219               0 :             bServiceDirty = TRUE;
    1220                 :             CPLCreateXMLElementAndValue( psService, "BandIdentifier", 
    1221               0 :                                          osBandIdentifier );
    1222                 :         }
    1223                 :     }
    1224                 : 
    1225                 : /* -------------------------------------------------------------------- */
    1226                 : /*      Do we have a temporal domain?  If so, try to identify a         */
    1227                 : /*      default time value.                                             */
    1228                 : /* -------------------------------------------------------------------- */
    1229               2 :     osDefaultTime = CPLGetXMLValue( psService, "DefaultTime", "" );
    1230                 :     CPLXMLNode * psTD = 
    1231               2 :         CPLGetXMLNode( psService, "CoverageOffering.domainSet.temporalDomain" );
    1232               2 :     CPLString osServiceURL = CPLGetXMLValue( psService, "ServiceURL", "" );
    1233               2 :     CPLString osCoverageExtra = CPLGetXMLValue( psService, "GetCoverageExtra", "" );
    1234                 : 
    1235               2 :     if( psTD != NULL )
    1236                 :     {
    1237                 :         CPLXMLNode *psTime;
    1238                 : 
    1239                 :         // collect all the allowed time positions.
    1240                 : 
    1241               0 :         for( psTime = psTD->psChild; psTime != NULL; psTime = psTime->psNext )
    1242                 :         {
    1243               0 :             if( psTime->eType == CXT_Element
    1244                 :                 && EQUAL(psTime->pszValue,"timePosition")
    1245                 :                 && psTime->psChild != NULL
    1246                 :                 && psTime->psChild->eType == CXT_Text )
    1247               0 :                 aosTimePositions.push_back( psTime->psChild->pszValue );
    1248                 :         }
    1249                 : 
    1250                 :         // we will default to the last - likely the most recent - entry.
    1251                 :         
    1252               0 :         if( aosTimePositions.size() > 0 
    1253                 :             && osDefaultTime == ""
    1254                 :             && osServiceURL.ifind("time=") == std::string::npos
    1255                 :             && osCoverageExtra.ifind("time=") == std::string::npos )
    1256                 :         {
    1257               0 :             osDefaultTime = aosTimePositions[aosTimePositions.size()-1];
    1258                 : 
    1259               0 :             bServiceDirty = TRUE;
    1260                 :             CPLCreateXMLElementAndValue( psService, "DefaultTime", 
    1261               0 :                                          osDefaultTime );
    1262                 :         }
    1263                 :     }
    1264                 : 
    1265               2 :     return TRUE;
    1266                 : }
    1267                 : 
    1268                 : /************************************************************************/
    1269                 : /*                          ParseBoundingBox()                          */
    1270                 : /************************************************************************/
    1271                 : 
    1272               0 : static int ParseBoundingBox( CPLXMLNode *psBoundingBox, CPLString &osCRS, 
    1273                 :                              double &dfLowerX, double &dfLowerY, 
    1274                 :                              double &dfUpperX, double &dfUpperY )
    1275                 : 
    1276                 : {
    1277               0 :     int nRet = TRUE;
    1278                 : 
    1279               0 :     osCRS = CPLGetXMLValue( psBoundingBox, "crs", "" );
    1280                 : 
    1281                 :     char **papszLC = CSLTokenizeStringComplex( 
    1282                 :         CPLGetXMLValue( psBoundingBox, "LowerCorner", ""),
    1283               0 :         " ", FALSE, FALSE );
    1284                 :     char **papszUC = CSLTokenizeStringComplex( 
    1285                 :         CPLGetXMLValue( psBoundingBox, "UpperCorner", ""),
    1286               0 :         " ", FALSE, FALSE );
    1287                 : 
    1288               0 :     if( CSLCount(papszLC) >= 2 && CSLCount(papszUC) >= 2 )
    1289                 :     {
    1290               0 :         dfLowerX = atof(papszLC[0]);
    1291               0 :         dfLowerY = atof(papszLC[1]);
    1292               0 :         dfUpperX = atof(papszUC[0]);
    1293               0 :         dfUpperY = atof(papszUC[1]);
    1294                 :     }
    1295                 :     else
    1296               0 :         nRet = FALSE;
    1297                 :     
    1298               0 :     CSLDestroy( papszUC );
    1299               0 :     CSLDestroy( papszLC );
    1300                 : 
    1301               0 :     return nRet;
    1302                 : }
    1303                 : 
    1304                 : /************************************************************************/
    1305                 : /*                          ExtractGridInfo()                           */
    1306                 : /*                                                                      */
    1307                 : /*      Collect info about grid from describe coverage for WCS 1.1      */
    1308                 : /*      and above.                                                      */
    1309                 : /************************************************************************/
    1310                 : 
    1311               2 : int WCSDataset::ExtractGridInfo()
    1312                 : 
    1313                 : {
    1314               2 :     if( nVersion == 100 )
    1315               2 :         return ExtractGridInfo100();
    1316                 : 
    1317               0 :     CPLXMLNode * psCO = CPLGetXMLNode( psService, "CoverageDescription" );
    1318                 : 
    1319               0 :     if( psCO == NULL )
    1320               0 :         return FALSE;
    1321                 : 
    1322                 : /* -------------------------------------------------------------------- */
    1323                 : /*      We need to strip off name spaces so it is easier to             */
    1324                 : /*      searchfor plain gml names.                                      */
    1325                 : /* -------------------------------------------------------------------- */
    1326               0 :     CPLStripXMLNamespace( psCO, NULL, TRUE );
    1327                 : 
    1328                 : /* -------------------------------------------------------------------- */
    1329                 : /*      Verify we have a SpatialDomain and GridCRS.                     */
    1330                 : /* -------------------------------------------------------------------- */
    1331                 :     CPLXMLNode *psSD = 
    1332               0 :         CPLGetXMLNode( psCO, "Domain.SpatialDomain" );
    1333                 :     CPLXMLNode *psGCRS = 
    1334               0 :         CPLGetXMLNode( psSD, "GridCRS" );
    1335                 : 
    1336               0 :     if( psSD == NULL || psGCRS == NULL )
    1337                 :     {
    1338                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1339                 :                   "Unable to find GridCRS in CoverageDescription,\n"
    1340               0 :                   "unable to process WCS Coverage." );
    1341               0 :         return FALSE;
    1342                 :     }
    1343                 : 
    1344                 : /* -------------------------------------------------------------------- */
    1345                 : /*      Extract Geotransform from GridCRS.                              */
    1346                 : /* -------------------------------------------------------------------- */
    1347                 :     const char *pszGridType = CPLGetXMLValue( psGCRS, "GridType",
    1348               0 :                                               "urn:ogc:def:method:WCS::2dSimpleGrid" );
    1349                 : 
    1350                 :     char **papszOriginTokens = 
    1351                 :         CSLTokenizeStringComplex( CPLGetXMLValue( psGCRS, "GridOrigin", ""),
    1352               0 :                                   " ", FALSE, FALSE );
    1353                 :     char **papszOffsetTokens = 
    1354                 :         CSLTokenizeStringComplex( CPLGetXMLValue( psGCRS, "GridOffsets", ""),
    1355               0 :                                   " ", FALSE, FALSE );
    1356                 : 
    1357               0 :     if( strstr(pszGridType,":2dGridIn2dCrs") 
    1358                 :         || strstr(pszGridType,":2dGridin2dCrs") )
    1359                 :     {
    1360               0 :         if( CSLCount(papszOffsetTokens) == 4
    1361                 :             && CSLCount(papszOriginTokens) == 2 )
    1362                 :         {
    1363               0 :             adfGeoTransform[0] = atof(papszOriginTokens[0]);
    1364               0 :             adfGeoTransform[1] = atof(papszOffsetTokens[0]);
    1365               0 :             adfGeoTransform[2] = atof(papszOffsetTokens[1]);
    1366               0 :             adfGeoTransform[3] = atof(papszOriginTokens[1]);
    1367               0 :             adfGeoTransform[4] = atof(papszOffsetTokens[2]);
    1368               0 :             adfGeoTransform[5] = atof(papszOffsetTokens[3]);
    1369                 :         }
    1370                 :         else
    1371                 :         {
    1372                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1373                 :                       "2dGridIn2dCrs does not have expected GridOrigin or\n"
    1374               0 :                       "GridOffsets values - unable to process WCS coverage.");
    1375               0 :             return FALSE;
    1376                 :         }
    1377                 :     }
    1378                 : 
    1379               0 :     else if( strstr(pszGridType,":2dGridIn3dCrs") )
    1380                 :     {
    1381               0 :         if( CSLCount(papszOffsetTokens) == 6
    1382                 :             && CSLCount(papszOriginTokens) == 3 )
    1383                 :         {
    1384               0 :             adfGeoTransform[0] = atof(papszOriginTokens[0]);
    1385               0 :             adfGeoTransform[1] = atof(papszOffsetTokens[0]);
    1386               0 :             adfGeoTransform[2] = atof(papszOffsetTokens[1]);
    1387               0 :             adfGeoTransform[3] = atof(papszOriginTokens[1]);
    1388               0 :             adfGeoTransform[4] = atof(papszOffsetTokens[3]);
    1389               0 :             adfGeoTransform[5] = atof(papszOffsetTokens[4]);
    1390                 :         }
    1391                 :         else
    1392                 :         {
    1393                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1394                 :                       "2dGridIn3dCrs does not have expected GridOrigin or\n"
    1395               0 :                       "GridOffsets values - unable to process WCS coverage.");
    1396               0 :             return FALSE;
    1397                 :         }
    1398                 :     }
    1399                 :     
    1400               0 :     else if( strstr(pszGridType,":2dSimpleGrid") )
    1401                 :     {
    1402               0 :         if( CSLCount(papszOffsetTokens) == 2
    1403                 :             && CSLCount(papszOriginTokens) == 2 )
    1404                 :         {
    1405               0 :             adfGeoTransform[0] = atof(papszOriginTokens[0]);
    1406               0 :             adfGeoTransform[1] = atof(papszOffsetTokens[0]);
    1407               0 :             adfGeoTransform[2] = 0.0;
    1408               0 :             adfGeoTransform[3] = atof(papszOriginTokens[1]);
    1409               0 :             adfGeoTransform[4] = 0.0;
    1410               0 :             adfGeoTransform[5] = atof(papszOffsetTokens[1]);
    1411                 :         }
    1412                 :         else
    1413                 :         {
    1414                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1415                 :                       "2dSimpleGrid does not have expected GridOrigin or\n"
    1416               0 :                       "GridOffsets values - unable to process WCS coverage.");
    1417               0 :             return FALSE;
    1418                 :         }
    1419                 :     }
    1420                 : 
    1421                 :     else
    1422                 :     {
    1423                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1424                 :                   "Unrecognised GridCRS.GridType value '%s',\n"
    1425                 :                   "unable to process WCS coverage.",
    1426               0 :                   pszGridType );
    1427               0 :         return FALSE;
    1428                 :     }
    1429                 : 
    1430               0 :     CSLDestroy( papszOffsetTokens );
    1431               0 :     CSLDestroy( papszOriginTokens );
    1432                 : 
    1433                 :     // GridOrigin is center of pixel ... offset half pixel to adjust. 
    1434                 : 
    1435               0 :     adfGeoTransform[0] -= (adfGeoTransform[1]+adfGeoTransform[2]) * 0.5; 
    1436               0 :     adfGeoTransform[3] -= (adfGeoTransform[4]+adfGeoTransform[5]) * 0.5; 
    1437                 : 
    1438                 : /* -------------------------------------------------------------------- */
    1439                 : /*      Establish our coordinate system.                                */
    1440                 : /* -------------------------------------------------------------------- */
    1441               0 :     osCRS = CPLGetXMLValue( psGCRS, "GridBaseCRS", "" );
    1442                 :     
    1443               0 :     if( strlen(osCRS) == 0 )
    1444                 :     {
    1445                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1446               0 :                   "Unable to find GridCRS.GridBaseCRS" );
    1447               0 :         return FALSE;
    1448                 :     }
    1449               0 :     else if( strstr(osCRS,":imageCRS") )
    1450                 :     {
    1451                 :         // raw image.
    1452                 :     }
    1453                 :     else
    1454                 :     {
    1455               0 :         OGRSpatialReference oSRS;
    1456               0 :         if( oSRS.importFromURN( osCRS ) == OGRERR_NONE )
    1457                 :         {
    1458               0 :             CPLFree( pszProjection );
    1459               0 :             oSRS.exportToWkt( &pszProjection );
    1460                 :         }
    1461                 :         else
    1462                 :         {
    1463                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1464                 :                       "Unable to interprete GridBaseCRS '%s'.",
    1465               0 :                       osCRS.c_str() );
    1466               0 :             return FALSE;
    1467               0 :         }
    1468                 :     }
    1469                 : 
    1470                 : /* -------------------------------------------------------------------- */
    1471                 : /*      Search for an ImageCRS for raster size.                         */
    1472                 : /* -------------------------------------------------------------------- */
    1473                 :     CPLXMLNode *psNode;
    1474                 : 
    1475               0 :     nRasterXSize = -1;
    1476               0 :     nRasterYSize = -1;
    1477               0 :     for( psNode = psSD->psChild; 
    1478                 :          psNode != NULL && nRasterXSize == -1;
    1479                 :          psNode = psNode->psNext )
    1480                 :     {
    1481               0 :         if( psNode->eType != CXT_Element
    1482                 :             || !EQUAL(psNode->pszValue,"BoundingBox") )
    1483               0 :             continue;
    1484                 : 
    1485                 :         double dfLX, dfLY, dfUX, dfUY;
    1486               0 :         CPLString osBBCRS;
    1487                 : 
    1488               0 :         if( ParseBoundingBox( psNode, osBBCRS, dfLX, dfLY, dfUX, dfUY )
    1489                 :             && strstr(osBBCRS,":imageCRS") 
    1490                 :             && dfLX == 0 && dfLY == 0 )
    1491                 :         {
    1492               0 :             nRasterXSize = (int) (dfUX + 1.01);
    1493               0 :             nRasterYSize = (int) (dfUY + 1.01);
    1494                 :         }
    1495                 :     }
    1496                 : 
    1497                 : /* -------------------------------------------------------------------- */
    1498                 : /*      Otherwise we search for a bounding box in our coordinate        */
    1499                 : /*      system and derive the size from that.                           */
    1500                 : /* -------------------------------------------------------------------- */
    1501               0 :     for( psNode = psSD->psChild; 
    1502                 :          psNode != NULL && nRasterXSize == -1;
    1503                 :          psNode = psNode->psNext )
    1504                 :     {
    1505               0 :         if( psNode->eType != CXT_Element
    1506                 :             || !EQUAL(psNode->pszValue,"BoundingBox") )
    1507               0 :             continue;
    1508                 : 
    1509                 :         double dfLX, dfLY, dfUX, dfUY;
    1510               0 :         CPLString osBBCRS;
    1511                 : 
    1512               0 :         if( ParseBoundingBox( psNode, osBBCRS, dfLX, dfLY, dfUX, dfUY )
    1513                 :             && osBBCRS == osCRS
    1514               0 :             && adfGeoTransform[2] == 0.0
    1515               0 :             && adfGeoTransform[4] == 0.0 )
    1516                 :         {
    1517                 :             nRasterXSize = 
    1518               0 :                 (int) ((dfUX - dfLX) / adfGeoTransform[1] + 1.01);
    1519                 :             nRasterYSize = 
    1520               0 :                 (int) ((dfUY - dfLY) / fabs(adfGeoTransform[5]) + 1.01);
    1521                 :         }
    1522                 :     }
    1523                 : 
    1524                 : /* -------------------------------------------------------------------- */
    1525                 : /*      Do we have a coordinate system override?                        */
    1526                 : /* -------------------------------------------------------------------- */
    1527               0 :     const char *pszProjOverride = CPLGetXMLValue( psService, "SRS", NULL );
    1528                 :     
    1529               0 :     if( pszProjOverride )
    1530                 :     {
    1531               0 :         OGRSpatialReference oSRS;
    1532                 :         
    1533               0 :         if( oSRS.SetFromUserInput( pszProjOverride ) != OGRERR_NONE )
    1534                 :         {
    1535                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1536                 :                       "<SRS> element contents not parsable:\n%s", 
    1537               0 :                       pszProjOverride );
    1538               0 :             return FALSE;
    1539                 :         }
    1540                 : 
    1541               0 :         CPLFree( pszProjection );
    1542               0 :         oSRS.exportToWkt( &pszProjection );
    1543                 :     }
    1544                 : 
    1545                 : /* -------------------------------------------------------------------- */
    1546                 : /*      Pick a format type if we don't already have one selected.       */
    1547                 : /*                                                                      */
    1548                 : /*      We will prefer anything that sounds like TIFF, otherwise        */
    1549                 : /*      falling back to the first supported format.  Should we          */
    1550                 : /*      consider preferring the nativeFormat if available?              */
    1551                 : /* -------------------------------------------------------------------- */
    1552               0 :     if( CPLGetXMLValue( psService, "PreferredFormat", NULL ) == NULL )
    1553                 :     {
    1554                 :         CPLXMLNode *psNode;
    1555               0 :         CPLString osPreferredFormat;
    1556                 : 
    1557               0 :         for( psNode = psCO->psChild; psNode != NULL; psNode = psNode->psNext )
    1558                 :         {
    1559               0 :             if( psNode->eType == CXT_Element 
    1560                 :                 && EQUAL(psNode->pszValue,"SupportedFormat") 
    1561                 :                 && psNode->psChild
    1562                 :                 && psNode->psChild->eType == CXT_Text )
    1563                 :             {
    1564               0 :                 if( strlen(osPreferredFormat) == 0 )
    1565               0 :                     osPreferredFormat = psNode->psChild->pszValue;
    1566                 : 
    1567               0 :                 if( strstr(psNode->psChild->pszValue,"tiff") != NULL 
    1568                 :                     || strstr(psNode->psChild->pszValue,"TIFF") != NULL
    1569                 :                     || strstr(psNode->psChild->pszValue,"Tiff") != NULL )
    1570                 :                 {
    1571               0 :                     osPreferredFormat = psNode->psChild->pszValue;
    1572               0 :                     break;
    1573                 :                 }
    1574                 :             }
    1575                 :         }
    1576                 : 
    1577               0 :         if( strlen(osPreferredFormat) > 0 )
    1578                 :         {
    1579               0 :             bServiceDirty = TRUE;
    1580                 :             CPLCreateXMLElementAndValue( psService, "PreferredFormat", 
    1581               0 :                                          osPreferredFormat );
    1582               0 :         }
    1583                 :     }
    1584                 : 
    1585                 : /* -------------------------------------------------------------------- */
    1586                 : /*      Try to identify a nodata value.  For now we only support the    */
    1587                 : /*      singleValue mechanism.                                          */
    1588                 : /* -------------------------------------------------------------------- */
    1589               0 :     if( CPLGetXMLValue( psService, "NoDataValue", NULL ) == NULL )
    1590                 :     {
    1591                 :         const char *pszSV = 
    1592               0 :             CPLGetXMLValue( psCO, "Range.Field.NullValue", NULL );
    1593                 :         
    1594               0 :         if( pszSV != NULL && (atof(pszSV) != 0.0 || *pszSV == '0') )
    1595                 :         {
    1596               0 :             bServiceDirty = TRUE;
    1597                 :             CPLCreateXMLElementAndValue( psService, "NoDataValue", 
    1598               0 :                                          pszSV );
    1599                 :         }
    1600                 :     }
    1601                 : 
    1602                 : /* -------------------------------------------------------------------- */
    1603                 : /*      Grab the field name, if possible.                               */
    1604                 : /* -------------------------------------------------------------------- */
    1605               0 :     if( CPLGetXMLValue( psService, "FieldName", NULL ) == NULL )
    1606                 :     {
    1607                 :         CPLString osFieldName = 
    1608               0 :             CPLGetXMLValue( psCO, "Range.Field.Identifier", "" );
    1609                 :         
    1610               0 :         if( strlen(osFieldName) > 0 )
    1611                 :         {
    1612               0 :             bServiceDirty = TRUE;
    1613                 :             CPLCreateXMLElementAndValue( psService, "FieldName", 
    1614               0 :                                          osFieldName );
    1615                 :         }
    1616                 :         else
    1617                 :         {
    1618                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1619                 :                       "Unable to find required Identifier name %s for Range Field.",
    1620               0 :                       osCRS.c_str() );
    1621               0 :             return FALSE;
    1622               0 :         }
    1623                 :     }
    1624                 : 
    1625                 : /* -------------------------------------------------------------------- */
    1626                 : /*      Do we have a "Band" axis?  If so try to grab the bandcount      */
    1627                 : /*      and data type from it.                                          */
    1628                 : /* -------------------------------------------------------------------- */
    1629                 :     CPLXMLNode * psAxis = CPLGetXMLNode( 
    1630               0 :         psService, "CoverageDescription.Range.Field.Axis" );
    1631                 : 
    1632               0 :     if( (EQUAL(CPLGetXMLValue(psAxis,"Identifier",""),"Band")
    1633                 :          || EQUAL(CPLGetXMLValue(psAxis,"Identifier",""),"Bands"))
    1634                 :         && CPLGetXMLNode(psAxis,"AvailableKeys") != NULL )
    1635                 :     {
    1636               0 :         osBandIdentifier = CPLGetXMLValue(psAxis,"Identifier","");
    1637                 :         
    1638                 :         // verify keys are ascending starting at 1
    1639               0 :         CPLXMLNode *psValues = CPLGetXMLNode(psAxis,"AvailableKeys");
    1640                 :         CPLXMLNode *psSV;
    1641                 :         int iBand;
    1642                 :         
    1643               0 :         for( psSV = psValues->psChild, iBand = 1; 
    1644                 :              psSV != NULL; 
    1645                 :              psSV = psSV->psNext, iBand++ )
    1646                 :         {
    1647               0 :             if( psSV->eType != CXT_Element 
    1648                 :                 || !EQUAL(psSV->pszValue,"Key") 
    1649                 :                 || psSV->psChild == NULL
    1650                 :                 || psSV->psChild->eType != CXT_Text
    1651                 :                 || atoi(psSV->psChild->pszValue) != iBand )
    1652                 :             {
    1653               0 :                 osBandIdentifier = "";
    1654               0 :                 break;
    1655                 :             }
    1656                 :         }
    1657                 :         
    1658               0 :         if( strlen(osBandIdentifier) )
    1659                 :         {
    1660               0 :             bServiceDirty = TRUE;
    1661               0 :             if( CPLGetXMLValue(psService,"BandIdentifier",NULL) == NULL )
    1662                 :                 CPLCreateXMLElementAndValue( psService, "BandIdentifier", 
    1663               0 :                                              osBandIdentifier );
    1664                 : 
    1665               0 :             if( CPLGetXMLValue(psService,"BandCount",NULL) == NULL )
    1666                 :                 CPLCreateXMLElementAndValue( psService, "BandCount", 
    1667               0 :                                              CPLString().Printf("%d",iBand-1));
    1668                 :         }
    1669                 : 
    1670                 :         // Is this an ESRI server returning a GDAL recognised data type?
    1671               0 :         CPLString osDataType = CPLGetXMLValue( psAxis, "DataType", "" );
    1672               0 :         if( GDALGetDataTypeByName(osDataType) != GDT_Unknown 
    1673                 :             && CPLGetXMLValue(psService,"BandType",NULL) == NULL )
    1674                 :         {
    1675               0 :             bServiceDirty = TRUE;
    1676               0 :             CPLCreateXMLElementAndValue( psService, "BandType", osDataType );
    1677               0 :         }
    1678                 :     }
    1679                 : 
    1680               0 :     return TRUE;
    1681                 : }
    1682                 : 
    1683                 : /************************************************************************/
    1684                 : /*                            ProcessError()                            */
    1685                 : /*                                                                      */
    1686                 : /*      Process an HTTP error, reporting it via CPL, and destroying     */
    1687                 : /*      the HTTP result object.  Returns TRUE if there was an error,    */
    1688                 : /*      or FALSE if the result seems ok.                                */
    1689                 : /************************************************************************/
    1690                 : 
    1691               5 : int WCSDataset::ProcessError( CPLHTTPResult *psResult )
    1692                 : 
    1693                 : {
    1694                 : /* -------------------------------------------------------------------- */
    1695                 : /*      There isn't much we can do in this case.  Hopefully an error    */
    1696                 : /*      was already issued by CPLHTTPFetch()                            */
    1697                 : /* -------------------------------------------------------------------- */
    1698               5 :     if( psResult == NULL || psResult->nDataLen == 0 )
    1699                 :     {
    1700               0 :         CPLHTTPDestroyResult( psResult );
    1701               0 :         return TRUE;
    1702                 :     }
    1703                 : 
    1704                 : /* -------------------------------------------------------------------- */
    1705                 : /*      If we got an html document, we presume it is an error           */
    1706                 : /*      message and report it verbatim up to a certain size limit.      */
    1707                 : /* -------------------------------------------------------------------- */
    1708                 : 
    1709               5 :     if( psResult->pszContentType != NULL 
    1710                 :         && strstr(psResult->pszContentType, "html") != NULL )
    1711                 :     {
    1712               0 :         CPLString osErrorMsg = (char *) psResult->pabyData;
    1713                 : 
    1714               0 :         if( osErrorMsg.size() > 2048 )
    1715               0 :             osErrorMsg.resize( 2048 );
    1716                 : 
    1717                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    1718                 :                   "Malformed Result:\n%s", 
    1719               0 :                   osErrorMsg.c_str() );
    1720               0 :         CPLHTTPDestroyResult( psResult );
    1721               0 :         return TRUE;
    1722                 :     }
    1723                 : 
    1724                 : /* -------------------------------------------------------------------- */
    1725                 : /*      Does this look like a service exception?  We would like to      */
    1726                 : /*      check based on the Content-type, but this seems quite           */
    1727                 : /*      undependable, even from MapServer!                              */
    1728                 : /* -------------------------------------------------------------------- */
    1729               5 :     if( strstr((const char *)psResult->pabyData, "ServiceException") 
    1730                 :         || strstr((const char *)psResult->pabyData, "ExceptionReport") )
    1731                 :     {
    1732                 :         CPLXMLNode *psTree = CPLParseXMLString( (const char *) 
    1733               0 :                                                 psResult->pabyData );
    1734               0 :         const char *pszMsg = NULL;
    1735                 : 
    1736               0 :         CPLStripXMLNamespace( psTree, NULL, TRUE );
    1737                 : 
    1738                 :         // VERSION 1.0.0
    1739               0 :         if( psTree != NULL )
    1740                 :             pszMsg = CPLGetXMLValue(psTree,
    1741                 :                                     "=ServiceExceptionReport.ServiceException",
    1742               0 :                                     NULL );
    1743                 :         // VERSION 1.1.0
    1744               0 :         if( pszMsg == NULL )
    1745                 :             pszMsg = CPLGetXMLValue(psTree,
    1746                 :                                     "=ExceptionReport.Exception.ExceptionText",
    1747               0 :                                     NULL );
    1748                 : 
    1749               0 :         if( pszMsg )
    1750                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1751               0 :                       "%s", pszMsg );
    1752                 :         else
    1753                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1754                 :                       "Corrupt Service Exception:\n%s",
    1755               0 :                       (const char *) psResult->pabyData );
    1756                 :         
    1757               0 :         CPLDestroyXMLNode( psTree );
    1758               0 :         CPLHTTPDestroyResult( psResult );
    1759               0 :         return TRUE;
    1760                 :     }
    1761                 : 
    1762                 : 
    1763                 : /* -------------------------------------------------------------------- */
    1764                 : /*      Hopefully the error already issued by CPLHTTPFetch() is         */
    1765                 : /*      sufficient.                                                     */
    1766                 : /* -------------------------------------------------------------------- */
    1767               5 :     if( CPLGetLastErrorNo() != 0 )
    1768               0 :         return TRUE;
    1769                 : 
    1770               5 :     return FALSE;
    1771                 : }
    1772                 : 
    1773                 : /************************************************************************/
    1774                 : /*                       EstablishRasterDetails()                       */
    1775                 : /*                                                                      */
    1776                 : /*      Do a "test" coverage query to work out the number of bands,     */
    1777                 : /*      and pixel data type of the remote coverage.                     */
    1778                 : /************************************************************************/
    1779                 : 
    1780               2 : int WCSDataset::EstablishRasterDetails()
    1781                 : 
    1782                 : {
    1783               2 :     CPLXMLNode * psCO = CPLGetXMLNode( psService, "CoverageOffering" );
    1784                 : 
    1785               2 :     const char* pszCols = CPLGetXMLValue( psCO, "dimensionLimit.columns", NULL );
    1786               2 :     const char* pszRows = CPLGetXMLValue( psCO, "dimensionLimit.rows", NULL );
    1787               2 :     if( pszCols && pszRows )
    1788                 :     {
    1789               0 :         nMaxCols = atoi(pszCols);
    1790               0 :         nMaxRows = atoi(pszRows);
    1791               0 :         SetMetadataItem("MAXNCOLS", pszCols, "IMAGE_STRUCTURE" );
    1792               0 :         SetMetadataItem("MAXNROWS", pszRows, "IMAGE_STRUCTURE" );
    1793                 :     }
    1794                 : 
    1795                 : /* -------------------------------------------------------------------- */
    1796                 : /*      Do we already have bandcount and pixel type settings?           */
    1797                 : /* -------------------------------------------------------------------- */
    1798               2 :     if( CPLGetXMLValue( psService, "BandCount", NULL ) != NULL 
    1799                 :         && CPLGetXMLValue( psService, "BandType", NULL ) != NULL )
    1800               0 :         return TRUE;
    1801                 : 
    1802                 : /* -------------------------------------------------------------------- */
    1803                 : /*      Fetch a small block of raster data.                             */
    1804                 : /* -------------------------------------------------------------------- */
    1805               2 :     CPLHTTPResult *psResult = NULL;
    1806                 :     CPLErr eErr;
    1807                 :     
    1808               2 :     eErr = GetCoverage( 0, 0, 2, 2, 2, 2, 0, NULL, &psResult );
    1809               2 :     if( eErr != CE_None )
    1810               0 :         return FALSE;
    1811                 : 
    1812                 : /* -------------------------------------------------------------------- */
    1813                 : /*      Try and open result as a dataseat.                               */
    1814                 : /* -------------------------------------------------------------------- */
    1815               2 :     GDALDataset *poDS = GDALOpenResult( psResult );
    1816                 : 
    1817               2 :     if( poDS == NULL )
    1818               0 :         return FALSE;
    1819                 : 
    1820               2 :     const char* pszPrj = poDS->GetProjectionRef();
    1821               2 :     if( pszPrj && strlen(pszPrj) > 0 )
    1822                 :     {
    1823               2 :         if( pszProjection )
    1824               2 :             CPLFree( pszProjection );
    1825                 : 
    1826               2 :         pszProjection = CPLStrdup( pszPrj );
    1827                 :     }
    1828                 : 
    1829                 : /* -------------------------------------------------------------------- */
    1830                 : /*      Record details.                                                 */
    1831                 : /* -------------------------------------------------------------------- */
    1832               2 :     if( poDS->GetRasterCount() < 1 )
    1833                 :     {
    1834               0 :         delete poDS;
    1835               0 :         return FALSE;
    1836                 :     }
    1837                 :     
    1838               2 :     if( CPLGetXMLValue(psService,"BandCount",NULL) == NULL )
    1839                 :         CPLCreateXMLElementAndValue( 
    1840                 :             psService, "BandCount", 
    1841               2 :             CPLString().Printf("%d",poDS->GetRasterCount()));
    1842                 :     
    1843                 :     CPLCreateXMLElementAndValue( 
    1844                 :         psService, "BandType", 
    1845               2 :         GDALGetDataTypeName(poDS->GetRasterBand(1)->GetRasterDataType()) );
    1846                 : 
    1847               2 :     bServiceDirty = TRUE;
    1848                 :     
    1849                 : /* -------------------------------------------------------------------- */
    1850                 : /*      Cleanup                                                         */
    1851                 : /* -------------------------------------------------------------------- */
    1852               2 :     delete poDS;
    1853                 :     
    1854               2 :     FlushMemoryResult();
    1855                 : 
    1856               2 :     return TRUE;
    1857                 : }
    1858                 : 
    1859                 : /************************************************************************/
    1860                 : /*                         FlushMemoryResult()                          */
    1861                 : /*                                                                      */
    1862                 : /*      This actually either cleans up the in memory /vsimem/           */
    1863                 : /*      temporary file, or the on disk temporary file.                  */
    1864                 : /************************************************************************/
    1865               8 : void WCSDataset::FlushMemoryResult()    
    1866                 :         
    1867                 : {
    1868               8 :     if( strlen(osResultFilename) > 0 )
    1869                 :     {
    1870               3 :         VSIUnlink( osResultFilename );
    1871               3 :         osResultFilename = "";
    1872                 :     }
    1873                 : 
    1874               8 :     if( pabySavedDataBuffer )
    1875                 :     {
    1876               3 :         CPLFree( pabySavedDataBuffer );
    1877               3 :         pabySavedDataBuffer = NULL;
    1878                 :     }
    1879               8 : }
    1880                 : 
    1881                 : /************************************************************************/
    1882                 : /*                           GDALOpenResult()                           */
    1883                 : /*                                                                      */
    1884                 : /*      Open a CPLHTTPResult as a GDALDataset (if possible).  First     */
    1885                 : /*      attempt is to open handle it "in memory".  Eventually we        */
    1886                 : /*      will add support for handling it on file if necessary.          */
    1887                 : /*                                                                      */
    1888                 : /*      This method will free CPLHTTPResult, the caller should not      */
    1889                 : /*      access it after the call.                                       */
    1890                 : /************************************************************************/
    1891                 : 
    1892               3 : GDALDataset *WCSDataset::GDALOpenResult( CPLHTTPResult *psResult )
    1893                 : 
    1894                 : {
    1895               3 :     FlushMemoryResult();
    1896                 : 
    1897                 :     CPLDebug( "WCS", "GDALOpenResult() on content-type: %s",
    1898               3 :               psResult->pszContentType );
    1899                 : 
    1900                 : /* -------------------------------------------------------------------- */
    1901                 : /*      If this is multipart/related content type, we should search     */
    1902                 : /*      for the second part.                                            */
    1903                 : /* -------------------------------------------------------------------- */
    1904               3 :     GByte *pabyData = psResult->pabyData;
    1905               3 :     int    nDataLen = psResult->nDataLen;
    1906                 : 
    1907               3 :     if( psResult->pszContentType 
    1908                 :         && strstr(psResult->pszContentType,"multipart") 
    1909                 :         && CPLHTTPParseMultipartMime(psResult) )
    1910                 :     {
    1911               0 :         if( psResult->nMimePartCount > 1 )
    1912                 :         {
    1913               0 :             pabyData = psResult->pasMimePart[1].pabyData;
    1914               0 :             nDataLen = psResult->pasMimePart[1].nDataLen;
    1915                 : 
    1916               0 :             if (CSLFindString(psResult->pasMimePart[1].papszHeaders,
    1917                 :                               "Content-Transfer-Encoding: base64") != -1)
    1918                 :             {
    1919               0 :                 nDataLen = CPLBase64DecodeInPlace(pabyData);
    1920                 :             }
    1921                 :         }
    1922                 :     }
    1923                 : 
    1924                 : /* -------------------------------------------------------------------- */
    1925                 : /*      Create a memory file from the result.                           */
    1926                 : /* -------------------------------------------------------------------- */
    1927                 :     // Eventually we should be looking at mime info and stuff to figure
    1928                 :     // out an optimal filename, but for now we just use a fixed one.
    1929                 :     osResultFilename.Printf( "/vsimem/wcs/%p/wcsresult.dat", 
    1930               3 :                              this );
    1931                 : 
    1932                 :     VSILFILE *fp = VSIFileFromMemBuffer( osResultFilename, pabyData, nDataLen,
    1933               3 :                                      FALSE );
    1934                 : 
    1935               3 :     if( fp == NULL )
    1936                 :     {
    1937               0 :         CPLHTTPDestroyResult(psResult);
    1938               0 :         return NULL;
    1939                 :     }
    1940                 : 
    1941               3 :     VSIFCloseL( fp );
    1942                 : 
    1943                 : /* -------------------------------------------------------------------- */
    1944                 : /*      Try opening this result as a gdaldataset.                       */
    1945                 : /* -------------------------------------------------------------------- */
    1946                 :     GDALDataset *poDS = (GDALDataset *) 
    1947               3 :         GDALOpen( osResultFilename, GA_ReadOnly );
    1948                 : 
    1949                 : /* -------------------------------------------------------------------- */
    1950                 : /*      If opening it in memory didn't work, perhaps we need to         */
    1951                 : /*      write to a temp file on disk?                                   */
    1952                 : /* -------------------------------------------------------------------- */
    1953               3 :     if( poDS == NULL )
    1954                 :     {
    1955               0 :         CPLString osTempFilename;
    1956                 :         VSILFILE *fpTemp;
    1957                 :         
    1958               0 :         osTempFilename.Printf( "/tmp/%p_wcs.dat", this );
    1959                 :                                
    1960               0 :         fpTemp = VSIFOpenL( osTempFilename, "wb" );
    1961               0 :         if( fpTemp == NULL )
    1962                 :         {
    1963                 :             CPLError( CE_Failure, CPLE_OpenFailed, 
    1964                 :                       "Failed to create temporary file:%s", 
    1965               0 :                       osTempFilename.c_str() );
    1966                 :         }
    1967                 :         else
    1968                 :         {
    1969               0 :             if( VSIFWriteL( pabyData, nDataLen, 1, fpTemp )
    1970                 :                 != 1 )
    1971                 :             {
    1972                 :                 CPLError( CE_Failure, CPLE_OpenFailed, 
    1973                 :                           "Failed to write temporary file:%s", 
    1974               0 :                           osTempFilename.c_str() );
    1975               0 :                 VSIFCloseL( fpTemp );
    1976               0 :                 VSIUnlink( osTempFilename );
    1977                 :             }
    1978                 :             else
    1979                 :             {
    1980               0 :                 VSIFCloseL( fpTemp );
    1981               0 :                 VSIUnlink( osResultFilename );
    1982               0 :                 osResultFilename = osTempFilename;
    1983                 : 
    1984                 :                 poDS =  (GDALDataset *) 
    1985               0 :                     GDALOpen( osResultFilename, GA_ReadOnly );
    1986                 :             }
    1987               0 :         }
    1988                 :     }
    1989                 : 
    1990                 : /* -------------------------------------------------------------------- */
    1991                 : /*      Steal the memory buffer from HTTP result.                       */
    1992                 : /* -------------------------------------------------------------------- */
    1993               3 :     pabySavedDataBuffer = psResult->pabyData;
    1994                 :         
    1995               3 :     psResult->pabyData = NULL;
    1996               3 :     psResult->nDataLen = psResult->nDataAlloc = 0;
    1997                 :     
    1998               3 :     if( poDS == NULL )
    1999               0 :         FlushMemoryResult();
    2000                 : 
    2001               3 :     CPLHTTPDestroyResult(psResult);
    2002                 : 
    2003               3 :     return poDS;
    2004                 : }
    2005                 : 
    2006                 : /************************************************************************/
    2007                 : /*                             Identify()                               */
    2008                 : /************************************************************************/
    2009                 : 
    2010            9245 : int WCSDataset::Identify( GDALOpenInfo * poOpenInfo )
    2011                 : 
    2012                 : {
    2013                 : /* -------------------------------------------------------------------- */
    2014                 : /*      Is this a WCS_GDAL service description file or "in url"         */
    2015                 : /*      equivelent?                                                     */
    2016                 : /* -------------------------------------------------------------------- */
    2017            9245 :     if( poOpenInfo->nHeaderBytes == 0
    2018                 :         && EQUALN((const char *) poOpenInfo->pszFilename,"<WCS_GDAL>",10) )
    2019               0 :         return TRUE;
    2020                 : 
    2021            9245 :     else if( poOpenInfo->nHeaderBytes >= 10
    2022                 :              && EQUALN((const char *) poOpenInfo->pabyHeader,"<WCS_GDAL>",10) )
    2023               0 :         return TRUE;
    2024                 : 
    2025                 : /* -------------------------------------------------------------------- */
    2026                 : /*      Is this apparently a WCS subdataset reference?                  */
    2027                 : /* -------------------------------------------------------------------- */
    2028            9245 :     else if( EQUALN((const char *) poOpenInfo->pszFilename,"WCS_SDS:",8) 
    2029                 :              && poOpenInfo->nHeaderBytes == 0 )
    2030               0 :         return TRUE;
    2031                 : 
    2032                 :     else
    2033            9245 :         return FALSE;
    2034                 : }
    2035                 : 
    2036                 : /************************************************************************/
    2037                 : /*                                Open()                                */
    2038                 : /************************************************************************/
    2039                 : 
    2040            2131 : GDALDataset *WCSDataset::Open( GDALOpenInfo * poOpenInfo )
    2041                 : 
    2042                 : {
    2043            2131 :     char **papszModifiers = NULL;
    2044                 : 
    2045                 : /* -------------------------------------------------------------------- */
    2046                 : /*      Is this a WCS_GDAL service description file or "in url"         */
    2047                 : /*      equivelent?                                                     */
    2048                 : /* -------------------------------------------------------------------- */
    2049            2131 :     CPLXMLNode *psService = NULL;
    2050                 : 
    2051            2132 :     if( poOpenInfo->nHeaderBytes == 0 
    2052                 :         && EQUALN((const char *) poOpenInfo->pszFilename,"<WCS_GDAL>",10) )
    2053                 :     {
    2054               1 :         psService = CPLParseXMLString( poOpenInfo->pszFilename );
    2055                 :     }
    2056            2131 :     else if( poOpenInfo->nHeaderBytes >= 10
    2057                 :              && EQUALN((const char *) poOpenInfo->pabyHeader,"<WCS_GDAL>",10) )
    2058                 :     {
    2059               1 :         psService = CPLParseXMLFile( poOpenInfo->pszFilename );
    2060                 :     }
    2061                 : /* -------------------------------------------------------------------- */
    2062                 : /*      Is this apparently a subdataset?                                */
    2063                 : /* -------------------------------------------------------------------- */
    2064            2129 :     else if( EQUALN((const char *) poOpenInfo->pszFilename,"WCS_SDS:",8) 
    2065                 :              && poOpenInfo->nHeaderBytes == 0 )
    2066                 :     {
    2067                 :         int iLast;
    2068                 : 
    2069                 :         papszModifiers = CSLTokenizeString2( poOpenInfo->pszFilename+8, ",",
    2070               0 :                                              CSLT_HONOURSTRINGS );
    2071                 : 
    2072               0 :         iLast = CSLCount(papszModifiers)-1;
    2073               0 :         if( iLast >= 0 )
    2074                 :         {
    2075               0 :             psService = CPLParseXMLFile( papszModifiers[iLast] );
    2076               0 :             CPLFree( papszModifiers[iLast] );
    2077               0 :             papszModifiers[iLast] = NULL;
    2078                 :         }
    2079                 : 
    2080                 :     }
    2081                 : 
    2082                 : /* -------------------------------------------------------------------- */
    2083                 : /*      Success so far?                                                 */
    2084                 : /* -------------------------------------------------------------------- */
    2085            2131 :     if( psService == NULL )
    2086                 :     {
    2087            2129 :         CSLDestroy( papszModifiers );
    2088            2129 :         return NULL;
    2089                 :     }
    2090                 :         
    2091                 : /* -------------------------------------------------------------------- */
    2092                 : /*      Confirm the requested access is supported.                      */
    2093                 : /* -------------------------------------------------------------------- */
    2094               2 :     if( poOpenInfo->eAccess == GA_Update )
    2095                 :     {
    2096               0 :         CSLDestroy( papszModifiers );
    2097               0 :         CPLDestroyXMLNode( psService );
    2098                 :         CPLError( CE_Failure, CPLE_NotSupported, 
    2099                 :                   "The WCS driver does not support update access to existing"
    2100               0 :                   " datasets.\n" );
    2101               0 :         return NULL;
    2102                 :     }
    2103                 :     
    2104                 : /* -------------------------------------------------------------------- */
    2105                 : /*      Check for required minimum fields.                              */
    2106                 : /* -------------------------------------------------------------------- */
    2107               2 :     if( !CPLGetXMLValue( psService, "ServiceURL", NULL )
    2108                 :         || !CPLGetXMLValue( psService, "CoverageName", NULL ) )
    2109                 :     {
    2110               0 :         CSLDestroy( papszModifiers );
    2111                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
    2112                 :                   "Missing one or both of ServiceURL and CoverageName elements.\n"
    2113               0 :                   "See WCS driver documentation for details on service description file format." );
    2114                 : 
    2115               0 :         CPLDestroyXMLNode( psService );
    2116               0 :         return NULL;
    2117                 :     }
    2118                 : 
    2119                 : /* -------------------------------------------------------------------- */
    2120                 : /*      What version are we working with?                               */
    2121                 : /* -------------------------------------------------------------------- */
    2122               2 :     const char *pszVersion = CPLGetXMLValue( psService, "Version", "1.0.0" );
    2123                 :     int nVersion;
    2124                 : 
    2125               2 :     if( EQUAL(pszVersion,"1.1.1") )
    2126               0 :         nVersion = 111;
    2127               2 :     else if( EQUAL(pszVersion,"1.1.0") )
    2128               0 :         nVersion = 110;
    2129               2 :     else if( EQUAL(pszVersion,"1.0.0") )
    2130               2 :         nVersion = 100;
    2131                 :     else
    2132                 :     {
    2133               0 :         CSLDestroy( papszModifiers );
    2134                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2135               0 :                   "WCS Version '%s' not supported.", pszVersion );
    2136               0 :         CPLDestroyXMLNode( psService );
    2137               0 :         return NULL;
    2138                 :     }
    2139                 : 
    2140                 : /* -------------------------------------------------------------------- */
    2141                 : /*      Create a corresponding GDALDataset.                             */
    2142                 : /* -------------------------------------------------------------------- */
    2143                 :     WCSDataset  *poDS;
    2144                 : 
    2145               2 :     poDS = new WCSDataset();
    2146                 : 
    2147               2 :     poDS->psService = psService;
    2148               2 :     poDS->SetDescription( poOpenInfo->pszFilename );
    2149               2 :     poDS->nVersion = nVersion;
    2150               2 :     poDS->papszSDSModifiers = papszModifiers;
    2151                 : 
    2152                 : /* -------------------------------------------------------------------- */
    2153                 : /*      Capture HTTP parameters.                                        */
    2154                 : /* -------------------------------------------------------------------- */
    2155                 :     const char  *pszParm;
    2156                 : 
    2157                 :     poDS->papszHttpOptions = 
    2158                 :         CSLSetNameValue(poDS->papszHttpOptions,
    2159                 :                         "TIMEOUT",
    2160               2 :                         CPLGetXMLValue( psService, "Timeout", "30" ) );
    2161                 : 
    2162               2 :     pszParm = CPLGetXMLValue( psService, "HTTPAUTH", NULL );
    2163               2 :     if( pszParm )
    2164                 :         poDS->papszHttpOptions = 
    2165                 :             CSLSetNameValue( poDS->papszHttpOptions, 
    2166               0 :                              "HTTPAUTH", pszParm );
    2167                 : 
    2168               2 :     pszParm = CPLGetXMLValue( psService, "USERPWD", NULL );
    2169               2 :     if( pszParm )
    2170                 :         poDS->papszHttpOptions = 
    2171                 :             CSLSetNameValue( poDS->papszHttpOptions, 
    2172               0 :                              "USERPWD", pszParm );
    2173                 : 
    2174                 : /* -------------------------------------------------------------------- */
    2175                 : /*      If we don't have the DescribeCoverage result for this           */
    2176                 : /*      coverage, fetch it now.                                         */
    2177                 : /* -------------------------------------------------------------------- */
    2178               2 :     if( CPLGetXMLNode( psService, "CoverageOffering" ) == NULL 
    2179                 :         && CPLGetXMLNode( psService, "CoverageDescription" ) == NULL )
    2180                 :     {
    2181               2 :         if( !poDS->DescribeCoverage() )
    2182                 :         {
    2183               0 :             delete poDS;
    2184               0 :             return NULL;
    2185                 :         }
    2186                 :     }
    2187                 : 
    2188                 : /* -------------------------------------------------------------------- */
    2189                 : /*      Extract coordinate system, grid size, and geotransform from     */
    2190                 : /*      the coverage description and/or service description             */
    2191                 : /*      information.                                                    */
    2192                 : /* -------------------------------------------------------------------- */
    2193               2 :     if( !poDS->ExtractGridInfo() )
    2194                 :     {
    2195               0 :         delete poDS;
    2196               0 :         return NULL;
    2197                 :     }
    2198                 :     
    2199               2 :     if( !poDS->EstablishRasterDetails() )
    2200                 :     {
    2201               0 :         delete poDS;
    2202               0 :         return NULL;
    2203                 :     }
    2204                 :     
    2205                 : /* -------------------------------------------------------------------- */
    2206                 : /*      Create band information objects.                                */
    2207                 : /* -------------------------------------------------------------------- */
    2208               2 :     int nBandCount = atoi(CPLGetXMLValue(psService,"BandCount","1"));
    2209                 :     int iBand;
    2210                 : 
    2211               2 :     if (!GDALCheckBandCount(nBandCount, 0))
    2212                 :     {
    2213               0 :         delete poDS;
    2214               0 :         return NULL;
    2215                 :     }
    2216                 :      
    2217              16 :     for( iBand = 0; iBand < nBandCount; iBand++ )
    2218               6 :         poDS->SetBand( iBand+1, new WCSRasterBand( poDS, iBand+1, -1 ) );
    2219                 : 
    2220                 : /* -------------------------------------------------------------------- */
    2221                 : /*      Set time metadata on the dataset if we are selecting a          */
    2222                 : /*      temporal slice.                                                 */
    2223                 : /* -------------------------------------------------------------------- */
    2224                 :     CPLString osTime = CSLFetchNameValueDef( poDS->papszSDSModifiers, "time", 
    2225               2 :                                              poDS->osDefaultTime );
    2226                 :     
    2227               2 :     if( osTime != "" )
    2228                 :         poDS->GDALMajorObject::SetMetadataItem( "TIME_POSITION", 
    2229               0 :                                                 osTime.c_str() );
    2230                 : 
    2231                 : /* -------------------------------------------------------------------- */
    2232                 : /*      Do we have a band identifier to select only a subset of bands?  */
    2233                 : /* -------------------------------------------------------------------- */
    2234               2 :     poDS->osBandIdentifier = CPLGetXMLValue(psService,"BandIdentifier","");
    2235                 : 
    2236                 : /* -------------------------------------------------------------------- */
    2237                 : /*      Do we have time based subdatasets?  If so, record them in       */
    2238                 : /*      metadata.  Note we don't do subdatasets if this is a            */
    2239                 : /*      subdataset or if this is an all-in-memory service.              */
    2240                 : /* -------------------------------------------------------------------- */
    2241               2 :     if( !EQUALN(poOpenInfo->pszFilename,"WCS_SDS:",8) 
    2242                 :         && !EQUALN(poOpenInfo->pszFilename,"<WCS_GDAL>",10) 
    2243                 :         && poDS->aosTimePositions.size() > 0 )
    2244                 :     {
    2245               0 :         char **papszSubdatasets = NULL;
    2246                 :         int iTime;
    2247                 : 
    2248               0 :         for( iTime = 0; iTime < (int)poDS->aosTimePositions.size(); iTime++ )
    2249                 :         {
    2250               0 :             CPLString osName;
    2251               0 :             CPLString osValue;
    2252                 :             
    2253               0 :             osName.Printf( "SUBDATASET_%d_NAME", iTime+1 );
    2254                 :             osValue.Printf( "WCS_SDS:time=\"%s\",%s", 
    2255                 :                            poDS->aosTimePositions[iTime].c_str(), 
    2256               0 :                            poOpenInfo->pszFilename );
    2257                 :             papszSubdatasets = CSLSetNameValue( papszSubdatasets, 
    2258               0 :                                                 osName, osValue );
    2259                 : 
    2260                 :             CPLString osCoverage = 
    2261               0 :                 CPLGetXMLValue( poDS->psService, "CoverageName", "" );
    2262                 : 
    2263               0 :             osName.Printf( "SUBDATASET_%d_DESC", iTime+1 );
    2264                 :             osValue.Printf( "Coverage %s at time %s", 
    2265                 :                             osCoverage.c_str(), 
    2266               0 :                             poDS->aosTimePositions[iTime].c_str() );
    2267                 :             papszSubdatasets = CSLSetNameValue( papszSubdatasets, 
    2268               0 :                                                 osName, osValue );
    2269                 :         }
    2270                 :         
    2271                 :         poDS->GDALMajorObject::SetMetadata( papszSubdatasets, 
    2272               0 :                                             "SUBDATASETS" );
    2273                 :         
    2274               0 :         CSLDestroy( papszSubdatasets );
    2275                 :     }
    2276                 : 
    2277                 : /* -------------------------------------------------------------------- */
    2278                 : /*      Initialize any PAM information.                                 */
    2279                 : /* -------------------------------------------------------------------- */
    2280               2 :     poDS->TryLoadXML();
    2281               2 :     return( poDS );
    2282                 : }
    2283                 : 
    2284                 : /************************************************************************/
    2285                 : /*                          GetGeoTransform()                           */
    2286                 : /************************************************************************/
    2287                 : 
    2288               1 : CPLErr WCSDataset::GetGeoTransform( double * padfTransform )
    2289                 : 
    2290                 : {
    2291               1 :     memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
    2292               1 :     return( CE_None );
    2293                 : }
    2294                 : 
    2295                 : /************************************************************************/
    2296                 : /*                          GetProjectionRef()                          */
    2297                 : /************************************************************************/
    2298                 : 
    2299               1 : const char *WCSDataset::GetProjectionRef()
    2300                 : 
    2301                 : {
    2302               1 :     const char* pszPrj = GDALPamDataset::GetProjectionRef();
    2303               1 :     if( pszPrj && strlen(pszPrj) > 0 )
    2304               0 :         return pszPrj;
    2305                 : 
    2306               1 :     if ( pszProjection && strlen(pszProjection) > 0 )
    2307               1 :         return pszProjection;
    2308                 : 
    2309               0 :     return( "" );
    2310                 : }
    2311                 : 
    2312                 : /************************************************************************/
    2313                 : /*                            GetFileList()                             */
    2314                 : /************************************************************************/
    2315                 : 
    2316               0 : char **WCSDataset::GetFileList()
    2317                 : 
    2318                 : {
    2319               0 :     char **papszFileList = GDALPamDataset::GetFileList();
    2320                 : 
    2321                 : /* -------------------------------------------------------------------- */
    2322                 : /*      ESRI also wishes to include service urls in the file list       */
    2323                 : /*      though this is not currently part of the general definition     */
    2324                 : /*      of GetFileList() for GDAL.                                      */
    2325                 : /* -------------------------------------------------------------------- */
    2326                 : #ifdef ESRI_BUILD
    2327                 :     CPLString file;
    2328                 :     file.Printf( "%s%s",
    2329                 :                  CPLGetXMLValue( psService, "ServiceURL", "" ),
    2330                 :                  CPLGetXMLValue( psService, "CoverageName", "" ) );
    2331                 :     papszFileList = CSLAddString( papszFileList, file.c_str() );
    2332                 : #endif /* def ESRI_BUILD */
    2333                 :     
    2334               0 :     return papszFileList;
    2335                 : }
    2336                 : 
    2337                 : /************************************************************************/
    2338                 : /*                            GetMetadata()                             */
    2339                 : /************************************************************************/
    2340                 : 
    2341               0 : char **WCSDataset::GetMetadata( const char *pszDomain )
    2342                 : 
    2343                 : {
    2344               0 :     if( pszDomain == NULL
    2345                 :         || !EQUAL(pszDomain,"xml:CoverageOffering") )
    2346               0 :         return GDALPamDataset::GetMetadata( pszDomain );
    2347                 : 
    2348                 :     
    2349               0 :     CPLXMLNode *psNode = CPLGetXMLNode( psService, "CoverageOffering" );
    2350                 : 
    2351               0 :     if( psNode == NULL )
    2352               0 :         psNode = CPLGetXMLNode( psService, "CoverageDescription" );
    2353                 : 
    2354               0 :     if( psNode == NULL )
    2355               0 :         return NULL;
    2356                 : 
    2357               0 :     if( apszCoverageOfferingMD[0] == NULL )
    2358                 :     {
    2359               0 :         CPLXMLNode *psNext = psNode->psNext;
    2360               0 :         psNode->psNext = NULL;
    2361                 : 
    2362               0 :         apszCoverageOfferingMD[0] = CPLSerializeXMLTree( psNode );
    2363                 : 
    2364               0 :         psNode->psNext = psNext;
    2365                 :     }
    2366                 : 
    2367               0 :     return apszCoverageOfferingMD;
    2368                 : }
    2369                 : 
    2370                 : 
    2371                 : /************************************************************************/
    2372                 : /*                          GDALRegister_WCS()                        */
    2373                 : /************************************************************************/
    2374                 : 
    2375             558 : void GDALRegister_WCS()
    2376                 : 
    2377                 : {
    2378                 :     GDALDriver  *poDriver;
    2379                 : 
    2380             558 :     if( GDALGetDriverByName( "WCS" ) == NULL )
    2381                 :     {
    2382             537 :         poDriver = new GDALDriver();
    2383                 :         
    2384             537 :         poDriver->SetDescription( "WCS" );
    2385                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    2386             537 :                                    "OGC Web Coverage Service" );
    2387                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2388             537 :                                    "frmt_wcs.html" );
    2389             537 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2390                 :         
    2391             537 :         poDriver->pfnOpen = WCSDataset::Open;
    2392             537 :         poDriver->pfnIdentify = WCSDataset::Identify;
    2393                 : 
    2394             537 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2395                 :     }
    2396             558 : }

Generated by: LCOV version 1.7