LTP GCOV extension - code coverage report
Current view: directory - frmts/wcs - wcsdataset.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 625
Code covered: 2.2 % Executed lines: 14

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

Generated by: LTP GCOV extension version 1.5