LCOV - code coverage report
Current view: directory - frmts/wms - rasterband.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 495 282 57.0 %
Date: 2013-03-30 Functions: 28 16 57.1 %

       1                 : /******************************************************************************
       2                 :  * $Id: rasterband.cpp 25776 2013-03-20 20:46:48Z rouault $
       3                 :  *
       4                 :  * Project:  WMS Client Driver
       5                 :  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
       6                 :  *           and other similar services.
       7                 :  * Author:   Adam Nowacki, nowak@xpam.de
       8                 :  *
       9                 :  ******************************************************************************
      10                 :  * Copyright (c) 2007, Adam Nowacki
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "stdinc.h"
      32                 : 
      33             695 : GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, double scale) {
      34                 :     //  printf("[%p] GDALWMSRasterBand::GDALWMSRasterBand(%p, %d, %f)\n", this, parent_dataset, band, scale);
      35             695 :     m_parent_dataset = parent_dataset;
      36             695 :     m_scale = scale;
      37             695 :     m_overview = -1;
      38             695 :     m_color_interp = GCI_Undefined;
      39                 : 
      40             695 :     poDS = parent_dataset;
      41             695 :     nRasterXSize = static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale + 0.5);
      42             695 :     nRasterYSize = static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale + 0.5);
      43             695 :     nBand = band;
      44             695 :     eDataType = m_parent_dataset->m_data_type;
      45             695 :     nBlockXSize = m_parent_dataset->m_block_size_x;
      46             695 :     nBlockYSize = m_parent_dataset->m_block_size_y;
      47             695 : }
      48                 : 
      49             695 : GDALWMSRasterBand::~GDALWMSRasterBand() {
      50            1352 :     for (std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin(); it != m_overviews.end(); ++it) {
      51             657 :         GDALWMSRasterBand *p = *it;
      52             657 :         delete p;
      53                 :     }
      54             695 : }
      55                 : 
      56               6 : char** GDALWMSRasterBand::BuildHTTPRequestOpts()
      57                 : {
      58               6 :     char **http_request_opts = NULL;
      59               6 :     if (m_parent_dataset->m_http_timeout != -1) {
      60               6 :         CPLString http_request_optstr;
      61               6 :         http_request_optstr.Printf("TIMEOUT=%d", m_parent_dataset->m_http_timeout);
      62               6 :         http_request_opts = CSLAddString(http_request_opts, http_request_optstr.c_str());
      63                 :     }
      64                 : 
      65               6 :     if (m_parent_dataset->m_osUserAgent.size() != 0)
      66                 :     {
      67               0 :         CPLString osUserAgentOptStr("USERAGENT=");
      68               0 :         osUserAgentOptStr += m_parent_dataset->m_osUserAgent;
      69               0 :         http_request_opts = CSLAddString(http_request_opts, osUserAgentOptStr.c_str());
      70                 :     }
      71               6 :     if (m_parent_dataset->m_osReferer.size() != 0)
      72                 :     {
      73               0 :         CPLString osRefererOptStr("REFERER=");
      74               0 :         osRefererOptStr += m_parent_dataset->m_osReferer;
      75               0 :         http_request_opts = CSLAddString(http_request_opts, osRefererOptStr.c_str());
      76                 :     }
      77               6 :     if (m_parent_dataset->m_unsafeSsl >= 1) {
      78               0 :         http_request_opts = CSLAddString(http_request_opts, "UNSAFESSL=1");
      79                 :     }
      80               6 :     if (m_parent_dataset->m_osUserPwd.size() != 0) 
      81                 :     {
      82               0 :         CPLString osUserPwdOptStr("USERPWD=");
      83               0 :         osUserPwdOptStr += m_parent_dataset->m_osUserPwd;
      84               0 :         http_request_opts = CSLAddString(http_request_opts, osUserPwdOptStr.c_str());
      85                 :     }
      86                 : 
      87               6 :    return http_request_opts;
      88                 : }
      89                 : 
      90               5 : CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0, int by0, int bx1, int by1, int advise_read) {
      91               5 :     CPLErr ret = CE_None;
      92                 :     int i;
      93                 : 
      94               5 :     int max_request_count = (bx1 - bx0 + 1) * (by1 - by0 + 1);
      95               5 :     int request_count = 0;
      96               5 :     CPLHTTPRequest *download_requests = NULL;
      97               5 :     GDALWMSCache *cache = m_parent_dataset->m_cache;
      98                 :     struct BlockXY {
      99                 :         int x, y;
     100               5 :     } *download_blocks = NULL;
     101               5 :     if (!m_parent_dataset->m_offline_mode) {
     102               5 :         download_requests = new CPLHTTPRequest[max_request_count];
     103               5 :         download_blocks = new BlockXY[max_request_count];
     104                 :     }
     105                 : 
     106               5 :     char **http_request_opts = BuildHTTPRequestOpts();
     107                 : 
     108              10 :     for (int iy = by0; iy <= by1; ++iy) {
     109              14 :         for (int ix = bx0; ix <= bx1; ++ix) {
     110               9 :             bool need_this_block = false;
     111               9 :             if (!advise_read) {
     112              32 :                 for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
     113              28 :                     if ((ix == x) && (iy == y) && (ib == nBand)) {
     114               5 :                         need_this_block = true;
     115                 :                     } else {
     116              18 :                         GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
     117              18 :                         if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
     118              18 :                         if (!band->IsBlockInCache(ix, iy)) need_this_block = true;
     119                 :                     }
     120                 :                 }
     121                 :             } else {
     122               0 :                 need_this_block = true;
     123                 :             }
     124               9 :             CPLString url;
     125               9 :             if (need_this_block) {
     126               9 :                 CPLString file_name;
     127               9 :                 AskMiniDriverForBlock(&url, ix, iy);
     128               9 :                 if ((cache != NULL) && (cache->Read(url.c_str(), &file_name) == CE_None)) {
     129               2 :                     if (advise_read) {
     130               0 :                         need_this_block = false;
     131                 :                     } else {
     132               2 :                         void *p = 0;
     133               2 :                         if ((ix == x) && (iy == y)) p = buffer;
     134               2 :                         if (ReadBlockFromFile(ix, iy, file_name.c_str(), nBand, p, 0) == CE_None) need_this_block = false;
     135                 :                     }
     136               9 :                 }
     137                 :             }
     138               9 :             if (need_this_block) {
     139               7 :                 if (m_parent_dataset->m_offline_mode) {
     140               0 :                     if (!advise_read) {
     141               0 :                         void *p = 0;
     142               0 :                         if ((ix == x) && (iy == y)) p = buffer;
     143               0 :                         if (ZeroBlock(ix, iy, nBand, p) != CE_None) {
     144               0 :                             CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
     145               0 :                             ret = CE_Failure;
     146                 :                         }
     147                 :                     }
     148                 :                 } else {
     149               7 :                     CPLHTTPInitializeRequest(&download_requests[request_count], url.c_str(), http_request_opts);
     150               7 :                     download_blocks[request_count].x = ix;
     151               7 :                     download_blocks[request_count].y = iy;
     152               7 :                     ++request_count;
     153                 :                 }
     154                 :             }
     155                 :         }
     156                 :     }
     157               5 :     if (http_request_opts != NULL) {
     158               5 :         CSLDestroy(http_request_opts);
     159                 :     }
     160                 : 
     161               5 :     if (request_count > 0) {
     162               4 :         char **opts = NULL;
     163               4 :         CPLString optstr;
     164               4 :         if (m_parent_dataset->m_http_max_conn != -1) {
     165               4 :             optstr.Printf("MAXCONN=%d", m_parent_dataset->m_http_max_conn);
     166               4 :             opts = CSLAddString(opts, optstr.c_str());
     167                 :         }
     168               4 :         if (CPLHTTPFetchMulti(download_requests, request_count, opts) != CE_None) {
     169               0 :             CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: CPLHTTPFetchMulti failed.");
     170               0 :             ret = CE_Failure;
     171                 :         }
     172               4 :         if (opts != NULL) {
     173               4 :             CSLDestroy(opts);
     174               4 :         }
     175                 :     }
     176                 : 
     177              12 :     for (i = 0; i < request_count; ++i) {
     178               7 :         if (ret == CE_None) {
     179              14 :             if ((download_requests[i].nStatus == 200) && (download_requests[i].pabyData != NULL) && (download_requests[i].nDataLen > 0)) {
     180               7 :                 CPLString file_name(BufferToVSIFile(download_requests[i].pabyData, download_requests[i].nDataLen));
     181               7 :                 if (file_name.size() > 0) {
     182               7 :                     bool wms_exception = false;
     183                 :                     /* check for error xml */
     184               7 :                     if (download_requests[i].nDataLen >= 20) {
     185               7 :                         const char *download_data = reinterpret_cast<char *>(download_requests[i].pabyData);
     186               7 :                         if (EQUALN(download_data, "<?xml ", 6) 
     187                 :                         || EQUALN(download_data, "<!DOCTYPE ", 10)
     188                 :                         || EQUALN(download_data, "<ServiceException", 17)) {
     189               0 :                             if (ReportWMSException(file_name.c_str()) != CE_None) {
     190               0 :                                 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned unknown exception.");
     191                 :                             }
     192               0 :                             wms_exception = true;
     193               0 :                             ret = CE_Failure;
     194                 :                         }
     195                 :                     }
     196               7 :                     if (ret == CE_None) {
     197               7 :                         if (advise_read && !m_parent_dataset->m_verify_advise_read) {
     198               0 :                             if (cache != NULL) {
     199               0 :                                 cache->Write(download_requests[i].pszURL, file_name);
     200                 :                             }
     201                 :                         } else {
     202               7 :                             void *p = 0;
     203               7 :                             if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
     204               7 :                             if (ReadBlockFromFile(download_blocks[i].x, download_blocks[i].y, file_name.c_str(), nBand, p, advise_read) == CE_None) {
     205               7 :                                 if (cache != NULL) {
     206               2 :                                     cache->Write(download_requests[i].pszURL, file_name);
     207                 :                                 }
     208                 :                             } else {
     209                 :                                 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ReadBlockFromFile (%s) failed.",
     210               0 :                                          download_requests[i].pszURL);
     211               0 :                                 ret = CE_Failure;
     212                 :                             }
     213                 :                         }
     214               0 :                     } else if( wms_exception && m_parent_dataset->m_zeroblock_on_serverexceptions ) {
     215               0 :                          void *p = 0;
     216               0 :                          if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
     217               0 :                          if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) {
     218               0 :                              CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
     219                 :                          } else {
     220               0 :                              ret = CE_None;
     221                 :                          }
     222                 : 
     223                 :                     }
     224               7 :                     VSIUnlink(file_name.c_str());
     225               7 :                 }
     226                 :             } else {
     227                 :                std::vector<int>::iterator zero_it = std::find(
     228                 :                      m_parent_dataset->m_http_zeroblock_codes.begin(),
     229                 :                      m_parent_dataset->m_http_zeroblock_codes.end(),
     230               0 :                      download_requests[i].nStatus);
     231               0 :                if ( zero_it != m_parent_dataset->m_http_zeroblock_codes.end() ) {
     232               0 :                     if (!advise_read) {
     233               0 :                         void *p = 0;
     234               0 :                         if ((download_blocks[i].x == x) && (download_blocks[i].y == y)) p = buffer;
     235               0 :                         if (ZeroBlock(download_blocks[i].x, download_blocks[i].y, nBand, p) != CE_None) {
     236               0 :                             CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: ZeroBlock failed.");
     237               0 :                             ret = CE_Failure;
     238                 :                         }
     239                 :                     }
     240                 :                 } else {
     241                 :                     CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to download block %d, %d.\n  URL: %s\n  HTTP status code: %d, error: %s.",
     242               0 :                         download_blocks[i].x, download_blocks[i].y, download_requests[i].pszURL, download_requests[i].nStatus, 
     243               0 :         download_requests[i].pszError ? download_requests[i].pszError : "(null)");
     244               0 :                     ret = CE_Failure;
     245                 :                 }
     246                 :             }
     247                 :         }
     248               7 :         CPLHTTPCleanupRequest(&download_requests[i]);
     249                 :     }
     250               5 :     if (!m_parent_dataset->m_offline_mode) {
     251               5 :         delete[] download_blocks;
     252               5 :         delete[] download_requests;
     253                 :     }
     254                 : 
     255               5 :     return ret;
     256                 : }
     257                 : 
     258               5 : CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer) {
     259               5 :     int bx0 = x;
     260               5 :     int by0 = y;
     261               5 :     int bx1 = x;
     262               5 :     int by1 = y;
     263                 : 
     264               5 :     if ((m_parent_dataset->m_hint.m_valid) && (m_parent_dataset->m_hint.m_overview == m_overview)) {
     265               5 :         int tbx0 = m_parent_dataset->m_hint.m_x0 / nBlockXSize;
     266               5 :         int tby0 = m_parent_dataset->m_hint.m_y0 / nBlockYSize;
     267               5 :         int tbx1 = (m_parent_dataset->m_hint.m_x0 + m_parent_dataset->m_hint.m_sx - 1) / nBlockXSize;
     268               5 :         int tby1 = (m_parent_dataset->m_hint.m_y0 + m_parent_dataset->m_hint.m_sy - 1) / nBlockYSize;
     269               5 :         if ((tbx0 <= bx0) && (tby0 <= by0) && (tbx1 >= bx1) && (tby1 >= by1)) {
     270               5 :             bx0 = tbx0;
     271               5 :             by0 = tby0;
     272               5 :             bx1 = tbx1;
     273               5 :             by1 = tby1;
     274                 :         }
     275                 :     }
     276                 : 
     277               5 :     CPLErr eErr = ReadBlocks(x, y, buffer, bx0, by0, bx1, by1, 0);
     278                 : 
     279               5 :     if ((m_parent_dataset->m_hint.m_valid) && (m_parent_dataset->m_hint.m_overview == m_overview))
     280                 :     {
     281               5 :         m_parent_dataset->m_hint.m_valid = false;
     282                 :     }
     283                 : 
     284               5 :     return eErr;
     285                 : }
     286                 : 
     287             220 : CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int pixel_space, int line_space) {
     288                 :     CPLErr ret;
     289                 : 
     290             220 :     if (rw != GF_Read) return CE_Failure;
     291             220 :     if (buffer == NULL) return CE_Failure;
     292             220 :     if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0)) return CE_None;
     293                 : 
     294             220 :     m_parent_dataset->m_hint.m_x0 = x0;
     295             220 :     m_parent_dataset->m_hint.m_y0 = y0;
     296             220 :     m_parent_dataset->m_hint.m_sx = sx;
     297             220 :     m_parent_dataset->m_hint.m_sy = sy;
     298             220 :     m_parent_dataset->m_hint.m_overview = m_overview;
     299             220 :     m_parent_dataset->m_hint.m_valid = true;
     300             220 :     ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, pixel_space, line_space);
     301             220 :     m_parent_dataset->m_hint.m_valid = false;
     302                 : 
     303             220 :     return ret;
     304                 : }
     305                 : 
     306               0 : int GDALWMSRasterBand::HasArbitraryOverviews() {
     307                 : //    return m_parent_dataset->m_mini_driver_caps.m_has_arb_overviews;
     308               0 :     return 0; // not implemented yet
     309                 : }
     310                 : 
     311               8 : int GDALWMSRasterBand::GetOverviewCount() {
     312               8 :     return m_overviews.size();
     313                 : }
     314                 : 
     315             105 : GDALRasterBand *GDALWMSRasterBand::GetOverview(int n) {
     316             105 :     if ((m_overviews.size() > 0) && (static_cast<size_t>(n) < m_overviews.size())) return m_overviews[n];
     317               0 :     else return NULL;
     318                 : }
     319                 : 
     320             657 : void GDALWMSRasterBand::AddOverview(double scale) {
     321             657 :     GDALWMSRasterBand *overview = new GDALWMSRasterBand(m_parent_dataset, nBand, scale);
     322             657 :     std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin();
     323            6193 :     for (; it != m_overviews.end(); ++it) {
     324            5536 :         GDALWMSRasterBand *p = *it;
     325            5536 :         if (p->m_scale < scale) break;
     326                 :     }
     327             657 :     m_overviews.insert(it, overview);
     328             657 :     it = m_overviews.begin();
     329            6850 :     for (int i = 0; it != m_overviews.end(); ++it, ++i) {
     330            6193 :         GDALWMSRasterBand *p = *it;
     331            6193 :         p->m_overview = i;
     332                 :     }
     333             657 : }
     334                 : 
     335              36 : bool GDALWMSRasterBand::IsBlockInCache(int x, int y) {
     336              36 :     bool ret = false;
     337              36 :     GDALRasterBlock *b = TryGetLockedBlockRef(x, y);
     338              36 :     if (b != NULL) {
     339               0 :         ret = true;
     340               0 :         b->DropLock();
     341                 :     }
     342              36 :     return ret;
     343                 : }
     344                 : 
     345                 : // This is the function that calculates the block coordinates for the fetch
     346               9 : void GDALWMSRasterBand::AskMiniDriverForBlock(CPLString *url, int x, int y)
     347                 : {
     348                 :     GDALWMSImageRequestInfo iri;
     349                 :     GDALWMSTiledImageRequestInfo tiri;
     350                 : 
     351               9 :     ComputeRequestInfo(iri, tiri, x, y);
     352                 : 
     353               9 :     m_parent_dataset->m_mini_driver->TiledImageRequest(url, iri, tiri);
     354               9 : }
     355                 : 
     356              10 : void GDALWMSRasterBand::ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
     357                 :                                            GDALWMSTiledImageRequestInfo &tiri,
     358                 :                                            int x, int y)
     359                 : {
     360              10 :     int x0 = MAX(0, x * nBlockXSize);
     361              10 :     int y0 = MAX(0, y * nBlockYSize);
     362              10 :     int x1 = MAX(0, (x + 1) * nBlockXSize);
     363              10 :     int y1 = MAX(0, (y + 1) * nBlockYSize);
     364              10 :     if (m_parent_dataset->m_clamp_requests) {
     365               8 :   x0 = MIN(x0, nRasterXSize);
     366               8 :   y0 = MIN(y0, nRasterYSize);
     367               8 :   x1 = MIN(x1, nRasterXSize);
     368               8 :   y1 = MIN(y1, nRasterYSize);
     369                 :     }
     370                 :     
     371              10 :     const double rx = (m_parent_dataset->m_data_window.m_x1 - m_parent_dataset->m_data_window.m_x0) / static_cast<double>(nRasterXSize);
     372              10 :     const double ry = (m_parent_dataset->m_data_window.m_y1 - m_parent_dataset->m_data_window.m_y0) / static_cast<double>(nRasterYSize);
     373                 :     /* Use different method for x0,y0 and x1,y1 to make sure calculated values are exact for corner requests */
     374              10 :     iri.m_x0 = x0 * rx + m_parent_dataset->m_data_window.m_x0;
     375              10 :     iri.m_y0 = y0 * ry + m_parent_dataset->m_data_window.m_y0;
     376              10 :     iri.m_x1 = m_parent_dataset->m_data_window.m_x1 - (nRasterXSize - x1) * rx;
     377              10 :     iri.m_y1 = m_parent_dataset->m_data_window.m_y1 - (nRasterYSize - y1) * ry;
     378              10 :     iri.m_sx = x1 - x0;
     379              10 :     iri.m_sy = y1 - y0;
     380                 : 
     381              10 :     int level = m_overview + 1;
     382              10 :     tiri.m_x = (m_parent_dataset->m_data_window.m_tx >> level) + x;
     383              10 :     tiri.m_y = (m_parent_dataset->m_data_window.m_ty >> level) + y;
     384              10 :     tiri.m_level = m_parent_dataset->m_data_window.m_tlevel - level;
     385              10 : }
     386                 : 
     387              61 : const char *GDALWMSRasterBand::GetMetadataItem( const char * pszName,
     388                 :                                                 const char * pszDomain )
     389                 : {
     390                 : /* ==================================================================== */
     391                 : /*      LocationInfo handling.                                          */
     392                 : /* ==================================================================== */
     393              61 :     if( pszDomain != NULL
     394                 :         && EQUAL(pszDomain,"LocationInfo")
     395                 :         && (EQUALN(pszName,"Pixel_",6) || EQUALN(pszName,"GeoPixel_",9)) )
     396                 :     {
     397                 :         int iPixel, iLine;
     398                 : 
     399                 : /* -------------------------------------------------------------------- */
     400                 : /*      What pixel are we aiming at?                                    */
     401                 : /* -------------------------------------------------------------------- */
     402               1 :         if( EQUALN(pszName,"Pixel_",6) )
     403                 :         {
     404               0 :             if( sscanf( pszName+6, "%d_%d", &iPixel, &iLine ) != 2 )
     405               0 :                 return NULL;
     406                 :         }
     407               1 :         else if( EQUALN(pszName,"GeoPixel_",9) )
     408                 :         {
     409                 :             double adfGeoTransform[6];
     410                 :             double adfInvGeoTransform[6];
     411                 :             double dfGeoX, dfGeoY;
     412                 : 
     413                 :             {
     414               1 :                 CPLLocaleC oLocaleEnforcer;
     415               1 :                 if( sscanf( pszName+9, "%lf_%lf", &dfGeoX, &dfGeoY ) != 2 )
     416               0 :                     return NULL;
     417                 :             }
     418                 : 
     419               1 :             if( GetDataset() == NULL )
     420               0 :                 return NULL;
     421                 : 
     422               1 :             if( GetDataset()->GetGeoTransform( adfGeoTransform ) != CE_None )
     423               0 :                 return NULL;
     424                 : 
     425               1 :             if( !GDALInvGeoTransform( adfGeoTransform, adfInvGeoTransform ) )
     426               0 :                 return NULL;
     427                 : 
     428                 :             iPixel = (int) floor(
     429               1 :                 adfInvGeoTransform[0]
     430               1 :                 + adfInvGeoTransform[1] * dfGeoX
     431               1 :                 + adfInvGeoTransform[2] * dfGeoY );
     432                 :             iLine = (int) floor(
     433               1 :                 adfInvGeoTransform[3]
     434               1 :                 + adfInvGeoTransform[4] * dfGeoX
     435               1 :                 + adfInvGeoTransform[5] * dfGeoY );
     436                 : 
     437                 :             /* The GetDataset() for the WMS driver is always the main overview level, so rescale */
     438                 :             /* the values if we are an overview */
     439               1 :             if (m_overview >= 0)
     440                 :             {
     441               0 :                 iPixel = (int) (1.0 * iPixel * GetXSize() / GetDataset()->GetRasterBand(1)->GetXSize());
     442               0 :                 iLine = (int) (1.0 * iLine * GetYSize() / GetDataset()->GetRasterBand(1)->GetYSize());
     443                 :             }
     444                 :         }
     445                 :         else
     446               0 :             return NULL;
     447                 : 
     448               1 :         if( iPixel < 0 || iLine < 0
     449                 :             || iPixel >= GetXSize()
     450                 :             || iLine >= GetYSize() )
     451               0 :             return NULL;
     452                 : 
     453               1 :         if (nBand != 1)
     454                 :         {
     455               0 :             GDALRasterBand* poFirstBand = m_parent_dataset->GetRasterBand(1);
     456               0 :             if (m_overview >= 0)
     457               0 :                 poFirstBand = poFirstBand->GetOverview(m_overview);
     458               0 :             if (poFirstBand)
     459               0 :                 return poFirstBand->GetMetadataItem(pszName, pszDomain);
     460                 :         }
     461                 : 
     462                 :         GDALWMSImageRequestInfo iri;
     463                 :         GDALWMSTiledImageRequestInfo tiri;
     464               1 :         int nBlockXOff = iPixel / nBlockXSize;
     465               1 :         int nBlockYOff = iLine / nBlockYSize;
     466                 : 
     467               1 :         ComputeRequestInfo(iri, tiri, nBlockXOff, nBlockYOff);
     468                 : 
     469               1 :         CPLString url;
     470                 :         m_parent_dataset->m_mini_driver->GetTiledImageInfo(&url,
     471                 :                                                            iri, tiri,
     472                 :                                                            iPixel % nBlockXSize,
     473               1 :                                                            iLine % nBlockXSize);
     474                 : 
     475                 : 
     476               1 :         char* pszRes = NULL;
     477                 : 
     478               1 :         if (url.size() != 0)
     479                 :         {
     480               1 :             if (url == osMetadataItemURL)
     481                 :             {
     482               0 :                 return osMetadataItem.size() != 0 ? osMetadataItem.c_str() : NULL;
     483                 :             }
     484               1 :             osMetadataItemURL = url;
     485                 : 
     486               1 :             char **http_request_opts = BuildHTTPRequestOpts();
     487               1 :             CPLHTTPResult* psResult = CPLHTTPFetch( url.c_str(), http_request_opts);
     488               1 :             if( psResult && psResult->pabyData )
     489               1 :                 pszRes = CPLStrdup((const char*) psResult->pabyData);
     490               1 :             CPLHTTPDestroyResult(psResult);
     491               1 :             CSLDestroy(http_request_opts);
     492                 :         }
     493                 : 
     494               1 :         if (pszRes)
     495                 :         {
     496               1 :             osMetadataItem = "<LocationInfo>";
     497               1 :             CPLPushErrorHandler(CPLQuietErrorHandler);
     498               1 :             CPLXMLNode* psXML = CPLParseXMLString(pszRes);
     499               1 :             CPLPopErrorHandler();
     500               2 :             if (psXML != NULL && psXML->eType == CXT_Element)
     501                 :             {
     502               1 :                 if (strcmp(psXML->pszValue, "?xml") == 0)
     503                 :                 {
     504               1 :                     if (psXML->psNext)
     505                 :                     {
     506               1 :                         char* pszXML = CPLSerializeXMLTree(psXML->psNext);
     507               1 :                         osMetadataItem += pszXML;
     508               1 :                         CPLFree(pszXML);
     509                 :                     }
     510                 :                 }
     511                 :                 else
     512                 :                 {
     513               0 :                     osMetadataItem += pszRes;
     514                 :                 }
     515                 :             }
     516                 :             else
     517                 :             {
     518               0 :                 char* pszEscapedXML = CPLEscapeString(pszRes, -1, CPLES_XML_BUT_QUOTES);
     519               0 :                 osMetadataItem += pszEscapedXML;
     520               0 :                 CPLFree(pszEscapedXML);
     521                 :             }
     522               1 :             if (psXML != NULL)
     523               1 :                 CPLDestroyXMLNode(psXML);
     524                 : 
     525               1 :             osMetadataItem += "</LocationInfo>";
     526               1 :             CPLFree(pszRes);
     527               1 :             return osMetadataItem.c_str();
     528                 :         }
     529                 :         else
     530                 :         {
     531               0 :             osMetadataItem = "";
     532               0 :             return NULL;
     533               0 :         }
     534                 :     }
     535                 : 
     536              60 :     return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     537                 : }
     538                 : 
     539               9 : CPLErr GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name, int to_buffer_band, void *buffer, int advise_read) {
     540               9 :     CPLErr ret = CE_None;
     541               9 :     GDALDataset *ds = 0;
     542               9 :     GByte *color_table = NULL;
     543                 :     int i;
     544                 : 
     545                 :     //CPLDebug("WMS", "ReadBlockFromFile: to_buffer_band=%d, (x,y)=(%d, %d)", to_buffer_band, x, y);
     546                 : 
     547                 :     /* expected size */
     548               9 :     const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) - MIN(MAX(0, x * nBlockXSize), nRasterXSize);
     549               9 :     const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) - MIN(MAX(0, y * nBlockYSize), nRasterYSize);
     550               9 :     ds = reinterpret_cast<GDALDataset*>(GDALOpen(file_name, GA_ReadOnly));
     551               9 :     if (ds != NULL) {
     552               9 :         int sx = ds->GetRasterXSize();
     553               9 :         int sy = ds->GetRasterYSize();
     554               9 :         bool accepted_as_no_alpha = false;  // if the request is for 4 bands but the wms returns 3  
     555                 :         /* Allow bigger than expected so pre-tiled constant size images work on corners */
     556               9 :         if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy)) {
     557                 :             CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect size %d x %d of downloaded block, expected %d x %d, max %d x %d.",
     558               0 :                 sx, sy, esx, esy, nBlockXSize, nBlockYSize);
     559               0 :             ret = CE_Failure;
     560                 :         }
     561               9 :         if (ret == CE_None) {
     562               9 :             int nDSRasterCount = ds->GetRasterCount();
     563               9 :             if (nDSRasterCount != m_parent_dataset->nBands) {
     564                 :                 /* Maybe its an image with color table */
     565               6 :                 bool accepted_as_ct = false;
     566               6 :                 if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1)) {
     567               0 :                     GDALRasterBand *rb = ds->GetRasterBand(1);
     568               0 :                     if (rb->GetRasterDataType() == GDT_Byte) {
     569               0 :                         GDALColorTable *ct = rb->GetColorTable();
     570               0 :                         if (ct != NULL) {
     571               0 :                             accepted_as_ct = true;
     572               0 :                             if (!advise_read) {
     573               0 :                                 color_table = new GByte[256 * 4];
     574               0 :                                 const int count = MIN(256, ct->GetColorEntryCount());
     575               0 :                                 for (i = 0; i < count; ++i) {
     576                 :                                     GDALColorEntry ce;
     577               0 :                                     ct->GetColorEntryAsRGB(i, &ce);
     578               0 :                                     color_table[i] = static_cast<GByte>(ce.c1);
     579               0 :                                     color_table[i + 256] = static_cast<GByte>(ce.c2);
     580               0 :                                     color_table[i + 512] = static_cast<GByte>(ce.c3);
     581               0 :                                     color_table[i + 768] = static_cast<GByte>(ce.c4);
     582                 :                                 }
     583               0 :                                 for (i = count; i < 256; ++i) {
     584               0 :                                     color_table[i] = 0;
     585               0 :                                     color_table[i + 256] = 0;
     586               0 :                                     color_table[i + 512] = 0;
     587               0 :                                     color_table[i + 768] = 0;
     588                 :                                 }
     589                 :                             }
     590                 :                         }
     591                 :                     }
     592                 :                 }
     593                 : 
     594               6 :                 if (nDSRasterCount == 4 && m_parent_dataset->nBands == 3)
     595                 :                 {
     596                 :                     /* metacarta TMS service sometimes return a 4 band PNG instead of the expected 3 band... */
     597                 :                 }
     598               0 :                 else if (!accepted_as_ct) {
     599               0 :                    if (ds->GetRasterCount()==3 && m_parent_dataset->nBands == 4 && (eDataType == GDT_Byte))
     600                 :                    { // WMS returned a file with no alpha so we will fill the alpha band with "opaque" 
     601               0 :                       accepted_as_no_alpha = true;
     602                 :                    }
     603                 :                    else
     604                 :                    {
     605                 :                       CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
     606               0 :                          nDSRasterCount, m_parent_dataset->nBands);
     607               0 :                       ret = CE_Failure;
     608                 :                    }
     609                 :                 }
     610                 :             }
     611                 :         }
     612               9 :         if (!advise_read) {
     613              32 :             for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
     614              23 :                 if (ret == CE_None) {
     615              23 :                     void *p = NULL;
     616              23 :                     GDALRasterBlock *b = NULL;
     617              28 :                     if ((buffer != NULL) && (ib == to_buffer_band)) {
     618               5 :                         p = buffer;
     619                 :                     } else {
     620              18 :                         GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
     621              18 :                         if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
     622              18 :                         if (!band->IsBlockInCache(x, y)) {
     623              18 :                             b = band->GetLockedBlockRef(x, y, true);
     624              18 :                             if (b != NULL) {
     625              18 :                                 p = b->GetDataRef();
     626              18 :                                 if (p == NULL) {
     627               0 :                                   CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
     628               0 :                                   ret = CE_Failure;
     629                 :                                 }
     630                 :                             }
     631                 :                         }
     632                 :                         else
     633                 :                         {
     634                 :                             //CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d) already in cache", band->GetBand(), x, y);
     635                 :                         }
     636                 :                     }
     637              23 :                     if (p != NULL) {
     638              23 :                         int pixel_space = GDALGetDataTypeSize(eDataType) / 8;
     639              23 :                         int line_space = pixel_space * nBlockXSize;
     640              23 :                         if (color_table == NULL) {
     641              23 :                             if( ib <= ds->GetRasterCount()) {
     642              23 :         GDALDataType dt=eDataType;
     643                 :         // Get the data from the PNG as stored instead of converting, if the server asks for that
     644                 :                                 // TODO: This hack is from #3493 - not sure it really belongs here.
     645              23 :         if ((GDT_Int16==dt)&&(GDT_UInt16==ds->GetRasterBand(ib)->GetRasterDataType()))
     646               2 :             dt=GDT_UInt16;
     647              23 :         if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, dt, 1, &ib, pixel_space, line_space, 0) != CE_None) {
     648               0 :             CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
     649               0 :             ret = CE_Failure;
     650                 :         }
     651                 :                             }
     652                 :                             else
     653                 :                             {  // parent expects 4 bands but file only has 3 so generate a all "opaque" 4th band
     654               0 :                                if (accepted_as_no_alpha)
     655                 :                                {
     656                 :                                   // the file had 3 bands and we are reading band 4 (Alpha) so fill with 255 (no alpha)
     657               0 :                                   GByte *byte_buffer = reinterpret_cast<GByte *>(p);
     658               0 :                                   for (int y = 0; y < sy; ++y) {
     659               0 :                                      for (int x = 0; x < sx; ++x) {
     660               0 :                                         const int offset = x + y * line_space;
     661               0 :                                         byte_buffer[offset] = 255;  // fill with opaque
     662                 :                                      }
     663                 :                                   }
     664                 :                                }
     665                 :                                else
     666                 :                                {  // we should never get here because this case was caught above
     667                 :                                   CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Incorrect bands count %d in downloaded block, expected %d.",
     668               0 :                                      ds->GetRasterCount(), m_parent_dataset->nBands);
     669               0 :                                   ret = CE_Failure;
     670                 :                                }     
     671                 :                             }
     672               0 :                         } else if (ib <= 4) {
     673               0 :                             if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0) != CE_None) {
     674               0 :                                 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
     675               0 :                                 ret = CE_Failure;
     676                 :                             }
     677               0 :                             if (ret == CE_None) {
     678               0 :                                 GByte *band_color_table = color_table + 256 * (ib - 1);
     679               0 :                                 GByte *byte_buffer = reinterpret_cast<GByte *>(p);
     680               0 :                                 for (int y = 0; y < sy; ++y) {
     681               0 :                                     for (int x = 0; x < sx; ++x) {
     682               0 :                                         const int offset = x + y * line_space;
     683               0 :                                         byte_buffer[offset] = band_color_table[byte_buffer[offset]];
     684                 :                                     }
     685                 :                                 }
     686                 :                             }
     687                 :                         } else {
     688               0 :                             CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Color table supports at most 4 components.");
     689               0 :                             ret = CE_Failure;
     690                 :                         }
     691                 :                     }
     692              23 :                     if (b != NULL) {
     693              18 :                         b->DropLock();
     694                 :                     }
     695                 :                 }
     696                 :             }
     697                 :         }
     698               9 :         GDALClose(ds);
     699                 :     } else {
     700               0 :         CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to open downloaded block.");
     701               0 :         ret = CE_Failure;
     702                 :     }
     703                 : 
     704               9 :     if (color_table != NULL) {
     705               0 :         delete[] color_table;
     706                 :     }
     707                 : 
     708               9 :     return ret;
     709                 : }
     710                 : 
     711               0 : CPLErr GDALWMSRasterBand::ZeroBlock(int x, int y, int to_buffer_band, void *buffer) {
     712               0 :     CPLErr ret = CE_None;
     713                 : 
     714               0 :     for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib) {
     715               0 :         if (ret == CE_None) {
     716               0 :             void *p = NULL;
     717               0 :             GDALRasterBlock *b = NULL;
     718               0 :             if ((buffer != NULL) && (ib == to_buffer_band)) {
     719               0 :                 p = buffer;
     720                 :             } else {
     721               0 :                 GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(m_parent_dataset->GetRasterBand(ib));
     722               0 :                 if (m_overview >= 0) band = static_cast<GDALWMSRasterBand *>(band->GetOverview(m_overview));
     723               0 :                 if (!band->IsBlockInCache(x, y)) {
     724               0 :                     b = band->GetLockedBlockRef(x, y, true);
     725               0 :                     if (b != NULL) {
     726               0 :                         p = b->GetDataRef();
     727               0 :                         if (p == NULL) {
     728               0 :                           CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: GetDataRef returned NULL.");
     729               0 :                           ret = CE_Failure;
     730                 :                         }
     731                 :                     }
     732                 :                 }
     733                 :             }
     734               0 :             if (p != NULL) {
     735               0 :                 unsigned char *b = reinterpret_cast<unsigned char *>(p);
     736               0 :                 int block_size = nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8);
     737               0 :                 for (int i = 0; i < block_size; ++i) b[i] = 0;
     738                 :             }
     739               0 :             if (b != NULL) {
     740               0 :                 b->DropLock();
     741                 :             }
     742                 :         }
     743                 :     }
     744                 : 
     745               0 :     return ret;
     746                 : }
     747                 : 
     748               0 : CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name) {
     749               0 :     CPLErr ret = CE_None;
     750               0 :     int reported_errors_count = 0;
     751                 : 
     752               0 :     CPLXMLNode *orig_root = CPLParseXMLFile(file_name);
     753               0 :     CPLXMLNode *root = orig_root;
     754               0 :     if (root != NULL) {
     755               0 :         root = CPLGetXMLNode(root, "=ServiceExceptionReport");
     756                 :     }
     757               0 :     if (root != NULL) {
     758               0 :         CPLXMLNode *n = CPLGetXMLNode(root, "ServiceException");
     759               0 :         while (n != NULL) {
     760               0 :             const char *exception = CPLGetXMLValue(n, "=ServiceException", "");
     761               0 :             const char *exception_code = CPLGetXMLValue(n, "=ServiceException.code", "");
     762               0 :             if (exception[0] != '\0') {
     763               0 :                 if (exception_code[0] != '\0') {
     764               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception code '%s': %s", exception_code, exception);
     765               0 :                     ++reported_errors_count;
     766                 :                 } else {
     767               0 :                     CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception: %s", exception);
     768               0 :                     ++reported_errors_count;
     769                 :                 }
     770               0 :             } else if (exception_code[0] != '\0') {
     771               0 :                 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: The server returned exception code '%s'.", exception_code);
     772               0 :                 ++reported_errors_count;
     773                 :             }
     774                 : 
     775               0 :             n = n->psNext;
     776               0 :             if (n != NULL) {
     777               0 :                 n = CPLGetXMLNode(n, "=ServiceException");
     778                 :             }
     779                 :         }
     780                 :     } else {
     781               0 :         ret = CE_Failure;
     782                 :     }
     783               0 :     if (orig_root != NULL) {
     784               0 :         CPLDestroyXMLNode(orig_root);
     785                 :     }
     786                 : 
     787               0 :     if (reported_errors_count == 0) {
     788               0 :         ret = CE_Failure;
     789                 :     }
     790                 : 
     791               0 :     return ret;
     792                 : }
     793                 : 
     794                 : 
     795               0 : CPLErr GDALWMSRasterBand::AdviseRead(int x0, int y0, int sx, int sy, int bsx, int bsy, GDALDataType bdt, char **options) {
     796                 : //    printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
     797               0 :     if (m_parent_dataset->m_offline_mode || !m_parent_dataset->m_use_advise_read) return CE_None;
     798               0 :     if (m_parent_dataset->m_cache == NULL) return CE_Failure;
     799                 : 
     800               0 :     int bx0 = x0 / nBlockXSize;
     801               0 :     int by0 = y0 / nBlockYSize;
     802               0 :     int bx1 = (x0 + sx - 1) / nBlockXSize;
     803               0 :     int by1 = (y0 + sy - 1) / nBlockYSize;
     804                 : 
     805               0 :     return ReadBlocks(0, 0, NULL, bx0, by0, bx1, by1, 1);
     806                 : }
     807                 : 
     808               0 : GDALColorInterp GDALWMSRasterBand::GetColorInterpretation() {
     809               0 :     return m_color_interp;
     810                 : }
     811                 : 
     812               5 : CPLErr GDALWMSRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
     813                 : {
     814               5 :     m_color_interp = eNewInterp;
     815               5 :     return CE_None;
     816                 : }
     817                 : 
     818                 : // Utility function, returns a value from a vector corresponding to the band index
     819                 : // or the first entry
     820               0 : static double getBandValue(std::vector<double> &v,size_t idx)
     821                 : {
     822               0 :     idx--;
     823               0 :     if (v.size()>idx) return v[idx];
     824               0 :     return v[0];
     825                 : }
     826                 : 
     827               0 : double GDALWMSRasterBand::GetNoDataValue( int *pbSuccess)
     828                 : {
     829               0 :     std::vector<double> &v=m_parent_dataset->vNoData;
     830               0 :     if (v.size()==0)
     831               0 :         return GDALPamRasterBand::GetNoDataValue(pbSuccess);
     832               0 :     if (pbSuccess) *pbSuccess=TRUE;
     833               0 :     return getBandValue(v,nBand);
     834                 : }
     835                 : 
     836               0 : double GDALWMSRasterBand::GetMinimum( int *pbSuccess)
     837                 : {
     838               0 :     std::vector<double> &v=m_parent_dataset->vMin;
     839               0 :     if (v.size()==0)
     840               0 :         return GDALPamRasterBand::GetMinimum(pbSuccess);
     841               0 :     if (pbSuccess) *pbSuccess=TRUE;
     842               0 :     return getBandValue(v,nBand);
     843                 : }
     844                 : 
     845               0 : double GDALWMSRasterBand::GetMaximum( int *pbSuccess)
     846                 : {
     847               0 :     std::vector<double> &v=m_parent_dataset->vMax;
     848               0 :     if (v.size()==0)
     849               0 :         return GDALPamRasterBand::GetMaximum(pbSuccess);
     850               0 :     if (pbSuccess) *pbSuccess=TRUE;
     851               0 :     return getBandValue(v,nBand);
     852                 : }
     853                 : 
     854               1 : GDALColorTable *GDALWMSRasterBand::GetColorTable()
     855                 : {
     856               1 :     return m_parent_dataset->m_poColorTable;
     857                 : }

Generated by: LCOV version 1.7