LCOV - code coverage report
Current view: top level - frmts/wms - gdalwmsrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 350 575 60.9 %
Date: 2024-11-21 22:18:42 Functions: 22 29 75.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  WMS Client Driver
       4             :  * Purpose:  GDALWMSRasterBand implementation.
       5             :  * Author:   Adam Nowacki, nowak@xpam.de
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2007, Adam Nowacki
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  * Copyright (c) 2017, Dmitry Baryshnikov, <polimax@mail.ru>
      11             :  * Copyright (c) 2017, NextGIS, <info@nextgis.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ****************************************************************************/
      15             : 
      16             : #include "wmsdriver.h"
      17             : 
      18             : #include <algorithm>
      19             : 
      20        6939 : GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band,
      21        6939 :                                      double scale)
      22             :     : m_parent_dataset(parent_dataset), m_scale(scale), m_overview(-1),
      23             :       m_color_interp(GCI_Undefined), m_nAdviseReadBX0(-1), m_nAdviseReadBY0(-1),
      24        6939 :       m_nAdviseReadBX1(-1), m_nAdviseReadBY1(-1)
      25             : {
      26             : #ifdef DEBUG_VERBOSE
      27             :     printf("[%p] GDALWMSRasterBand::GDALWMSRasterBand(%p, %d, %f)\n", /*ok*/
      28             :            this, parent_dataset, band, scale);
      29             : #endif
      30             : 
      31        6939 :     if (scale == 1.0)
      32        1328 :         poDS = parent_dataset;
      33             :     else
      34        5611 :         poDS = nullptr;
      35        6939 :     if (parent_dataset->m_mini_driver_caps.m_overview_dim_computation_method ==
      36             :         OVERVIEW_ROUNDED)
      37             :     {
      38        6909 :         nRasterXSize = static_cast<int>(
      39        6909 :             m_parent_dataset->m_data_window.m_sx * scale + 0.5);
      40        6909 :         nRasterYSize = static_cast<int>(
      41        6909 :             m_parent_dataset->m_data_window.m_sy * scale + 0.5);
      42             :     }
      43             :     else
      44             :     {
      45          30 :         nRasterXSize =
      46          30 :             static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale);
      47          30 :         nRasterYSize =
      48          30 :             static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale);
      49             :     }
      50        6939 :     nBand = band;
      51        6939 :     eDataType = m_parent_dataset->m_data_type;
      52        6939 :     nBlockXSize = m_parent_dataset->m_block_size_x;
      53        6939 :     nBlockYSize = m_parent_dataset->m_block_size_y;
      54        6939 : }
      55             : 
      56       20817 : GDALWMSRasterBand::~GDALWMSRasterBand()
      57             : {
      58       12550 :     while (!m_overviews.empty())
      59             :     {
      60        5611 :         delete m_overviews.back();
      61        5611 :         m_overviews.pop_back();
      62             :     }
      63       13878 : }
      64             : 
      65             : // Request for x, y but all blocks between bx0-bx1 and by0-by1 should be read
      66          36 : CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0,
      67             :                                      int by0, int bx1, int by1, int advise_read)
      68             : {
      69          36 :     CPLErr ret = CE_None;
      70             : 
      71             :     // Get a vector of requests large enough for this call
      72          36 :     std::vector<WMSHTTPRequest> requests(static_cast<size_t>(bx1 - bx0 + 1) *
      73          36 :                                          (by1 - by0 + 1));
      74             : 
      75          36 :     size_t count = 0;  // How many requests are valid
      76          36 :     GDALWMSCache *cache = m_parent_dataset->m_cache;
      77          36 :     int offline = m_parent_dataset->m_offline_mode;
      78          36 :     const char *const *options = m_parent_dataset->GetHTTPRequestOpts();
      79             : 
      80          77 :     for (int iy = by0; iy <= by1; ++iy)
      81             :     {
      82          97 :         for (int ix = bx0; ix <= bx1; ++ix)
      83             :         {
      84          56 :             WMSHTTPRequest &request = requests[count];
      85          56 :             request.x = ix;
      86          56 :             request.y = iy;
      87          56 :             bool need_this_block = false;
      88          56 :             if (!advise_read)
      89             :             {
      90         236 :                 for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
      91             :                 {
      92         180 :                     if ((ix == x) && (iy == y) && (ib == nBand))
      93             :                     {
      94          36 :                         need_this_block = true;
      95             :                     }
      96             :                     else
      97             :                     {
      98             :                         GDALWMSRasterBand *band =
      99             :                             static_cast<GDALWMSRasterBand *>(
     100         144 :                                 m_parent_dataset->GetRasterBand(ib));
     101         144 :                         if (m_overview >= 0)
     102             :                             band = static_cast<GDALWMSRasterBand *>(
     103          71 :                                 band->GetOverview(m_overview));
     104         144 :                         if (!band->IsBlockInCache(ix, iy))
     105         144 :                             need_this_block = true;
     106             :                     }
     107             :                 }
     108             :             }
     109             :             else
     110             :             {
     111           0 :                 need_this_block = true;
     112             :             }
     113             : 
     114          56 :             void *p = ((ix == x) && (iy == y)) ? buffer : nullptr;
     115          56 :             if (need_this_block)
     116             :             {
     117          56 :                 ret = AskMiniDriverForBlock(request, ix, iy);
     118          56 :                 if (ret != CE_None)
     119             :                 {
     120           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "%s",
     121             :                              request.Error.c_str());
     122           0 :                     ret = CE_Failure;
     123             :                 }
     124             :                 // A missing tile is signaled by setting a range of "none"
     125          56 :                 if (EQUAL(request.Range, "none"))
     126             :                 {
     127           0 :                     if (!advise_read)
     128             :                     {
     129           0 :                         if (EmptyBlock(ix, iy, nBand, p) != CE_None)
     130             :                         {
     131           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     132             :                                      "GDALWMS: EmptyBlock failed.");
     133           0 :                             ret = CE_Failure;
     134             :                         }
     135             :                     }
     136           0 :                     need_this_block = false;
     137             :                 }
     138          56 :                 if (ret == CE_None && cache != nullptr)
     139             :                 {
     140          32 :                     if (cache->GetItemStatus(request.URL) == CACHE_ITEM_OK)
     141             :                     {
     142          12 :                         if (advise_read)
     143             :                         {
     144           0 :                             need_this_block = false;
     145             :                         }
     146             :                         else
     147             :                         {
     148          12 :                             if (ReadBlockFromCache(request.URL, ix, iy, nBand,
     149          12 :                                                    p, 0) == CE_None)
     150             :                             {
     151          12 :                                 need_this_block = false;
     152             :                             }
     153             :                         }
     154             :                     }
     155             :                 }
     156             :             }
     157             : 
     158          56 :             if (need_this_block)
     159             :             {
     160          44 :                 if (offline)
     161             :                 {
     162           0 :                     if (!advise_read)
     163             :                     {
     164           0 :                         if (EmptyBlock(ix, iy, nBand, p) != CE_None)
     165             :                         {
     166           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     167             :                                      "GDALWMS: EmptyBlock failed.");
     168           0 :                             ret = CE_Failure;
     169             :                         }
     170             :                     }
     171             :                 }
     172             :                 else
     173             :                 {
     174          44 :                     request.options = options;
     175          44 :                     WMSHTTPInitializeRequest(&request);
     176          44 :                     count++;
     177             :                 }
     178             :             }
     179             :         }
     180             :     }
     181             : 
     182             :     // Fetch all the requests, OK to call with count of 0
     183          36 :     if (WMSHTTPFetchMulti(count ? &requests[0] : nullptr,
     184          36 :                           static_cast<int>(count)) != CE_None)
     185             :     {
     186           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     187             :                  "GDALWMS: CPLHTTPFetchMulti failed.");
     188           0 :         ret = CE_Failure;
     189             :     }
     190             : 
     191          80 :     for (size_t i = 0; i < count; ++i)
     192             :     {
     193          44 :         WMSHTTPRequest &request = requests[i];
     194          44 :         void *p = ((request.x == x) && (request.y == y)) ? buffer : nullptr;
     195          44 :         if (ret == CE_None)
     196             :         {
     197          50 :             int success = (request.nStatus == 200) ||
     198           6 :                           (!request.Range.empty() && request.nStatus == 206);
     199          44 :             if (success && (request.pabyData != nullptr) &&
     200          38 :                 (request.nDataLen > 0))
     201             :             {
     202             :                 CPLString file_name(
     203          76 :                     BufferToVSIFile(request.pabyData, request.nDataLen));
     204          38 :                 if (!file_name.empty())
     205             :                 {
     206             :                     /* check for error xml */
     207          38 :                     if (request.nDataLen >= 20)
     208             :                     {
     209          38 :                         const char *download_data =
     210             :                             reinterpret_cast<char *>(request.pabyData);
     211          38 :                         if (STARTS_WITH_CI(download_data, "<?xml ") ||
     212          38 :                             STARTS_WITH_CI(download_data, "<!DOCTYPE ") ||
     213          38 :                             STARTS_WITH_CI(download_data, "<ServiceException"))
     214             :                         {
     215           0 :                             if (ReportWMSException(file_name) != CE_None)
     216             :                             {
     217           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
     218             :                                          "GDALWMS: The server returned unknown "
     219             :                                          "exception.");
     220             :                             }
     221           0 :                             ret = CE_Failure;
     222             :                         }
     223             :                     }
     224          38 :                     if (ret == CE_None)
     225             :                     {
     226          38 :                         if (advise_read &&
     227           0 :                             !m_parent_dataset->m_verify_advise_read)
     228             :                         {
     229           0 :                             if (cache != nullptr)
     230           0 :                                 cache->Insert(request.URL, file_name);
     231             :                         }
     232             :                         else
     233             :                         {
     234          38 :                             ret = ReadBlockFromFile(file_name, request.x,
     235             :                                                     request.y, nBand, p,
     236             :                                                     advise_read);
     237          38 :                             if (ret == CE_None)
     238             :                             {
     239          38 :                                 if (cache != nullptr)
     240          18 :                                     cache->Insert(request.URL, file_name);
     241             :                             }
     242             :                             else
     243             :                             {
     244           0 :                                 CPLError(
     245             :                                     ret, CPLE_AppDefined,
     246             :                                     "GDALWMS: ReadBlockFromFile (%s) failed.",
     247             :                                     request.URL.c_str());
     248             :                             }
     249             :                         }
     250             :                     }
     251           0 :                     else if (m_parent_dataset->m_zeroblock_on_serverexceptions)
     252             :                     {
     253           0 :                         ret = EmptyBlock(request.x, request.y, nBand, p);
     254           0 :                         if (ret != CE_None)
     255           0 :                             CPLError(ret, CPLE_AppDefined,
     256             :                                      "GDALWMS: EmptyBlock failed.");
     257             :                     }
     258          38 :                     VSIUnlink(file_name);
     259          38 :                 }
     260             :             }
     261             :             else
     262             :             {  // HTTP error
     263             :                 // One more try to get cached block. For example if no web
     264             :                 // access available
     265           6 :                 CPLDebug("WMS", "ReadBlockFromCache");
     266             : 
     267           6 :                 if (m_parent_dataset->m_cache != nullptr)
     268           2 :                     ret = ReadBlockFromCache(request.URL, request.x, request.y,
     269             :                                              nBand, p, advise_read);
     270             :                 else
     271           4 :                     ret = CE_Failure;
     272             : 
     273           6 :                 if (ret != CE_None)
     274             :                 {
     275           6 :                     CPLDebug("WMS", "After ReadBlockFromCache");
     276          12 :                     if (m_parent_dataset->m_http_zeroblock_codes.find(
     277           6 :                             request.nStatus) !=
     278          12 :                         m_parent_dataset->m_http_zeroblock_codes.end())
     279             :                     {
     280           2 :                         if (!advise_read)
     281             :                         {
     282           2 :                             ret = EmptyBlock(request.x, request.y, nBand, p);
     283           2 :                             if (ret != CE_None)
     284           0 :                                 CPLError(ret, CPLE_AppDefined,
     285             :                                          "GDALWMS: EmptyBlock failed.");
     286             :                         }
     287             :                     }
     288             :                     else
     289             :                     {
     290           4 :                         ret = CE_Failure;
     291           7 :                         CPLError(ret, CPLE_AppDefined,
     292             :                                  "GDALWMS: Unable to download block %d, %d.\n"
     293             :                                  "URL: %s\n  HTTP status code: %d, error: %s.\n"
     294             :                                  "Add the HTTP status code to "
     295             :                                  "<ZeroBlockHttpCodes> to ignore this error "
     296             :                                  "(see http://www.gdal.org/frmt_wms.html).",
     297             :                                  request.x, request.y,
     298           4 :                                  !request.URL.empty() ? request.Error.c_str()
     299             :                                                       : "(null)",
     300             :                                  request.nStatus,
     301           4 :                                  !request.Error.empty() ? request.Error.c_str()
     302             :                                                         : "(null)");
     303             :                     }
     304             :                 }
     305             :             }
     306             :         }
     307             :     }
     308             : 
     309          72 :     return ret;
     310             : }
     311             : 
     312          36 : CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer)
     313             : {
     314          36 :     int bx0 = x;
     315          36 :     int by0 = y;
     316          36 :     int bx1 = x;
     317          36 :     int by1 = y;
     318             : 
     319          36 :     bool bCancelHint = false;
     320          36 :     if ((m_parent_dataset->m_hint.m_valid) &&
     321          36 :         (m_parent_dataset->m_hint.m_overview == m_overview))
     322             :     {
     323          36 :         int tbx0 = m_parent_dataset->m_hint.m_x0 / nBlockXSize;
     324          36 :         int tby0 = m_parent_dataset->m_hint.m_y0 / nBlockYSize;
     325          36 :         int tbx1 = (m_parent_dataset->m_hint.m_x0 +
     326          36 :                     m_parent_dataset->m_hint.m_sx - 1) /
     327          36 :                    nBlockXSize;
     328          36 :         int tby1 = (m_parent_dataset->m_hint.m_y0 +
     329          36 :                     m_parent_dataset->m_hint.m_sy - 1) /
     330          36 :                    nBlockYSize;
     331          36 :         if ((tbx0 <= x) && (tby0 <= y) && (tbx1 >= x) && (tby1 >= y))
     332             :         {
     333             :             // Avoid downloading a insane number of tiles at once.
     334             :             // Limit to 30x30 tiles centered around block of interest.
     335          36 :             bx0 = std::max(x - 15, tbx0);
     336          36 :             by0 = std::max(y - 15, tby0);
     337          36 :             bx1 = std::min(x + 15, tbx1);
     338          36 :             by1 = std::min(y + 15, tby1);
     339          36 :             bCancelHint =
     340          36 :                 (bx0 == tbx0 && by0 == tby0 && bx1 == tbx1 && by1 == tby1);
     341             :         }
     342             :     }
     343             : 
     344          36 :     CPLErr eErr = ReadBlocks(x, y, buffer, bx0, by0, bx1, by1, 0);
     345             : 
     346          36 :     if (bCancelHint)
     347             :     {
     348          36 :         m_parent_dataset->m_hint.m_valid = false;
     349             :     }
     350             : 
     351          36 :     return eErr;
     352             : }
     353             : 
     354          88 : CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx,
     355             :                                     int sy, void *buffer, int bsx, int bsy,
     356             :                                     GDALDataType bdt, GSpacing nPixelSpace,
     357             :                                     GSpacing nLineSpace,
     358             :                                     GDALRasterIOExtraArg *psExtraArg)
     359             : {
     360             :     CPLErr ret;
     361             : 
     362          88 :     if (rw != GF_Read)
     363           0 :         return CE_Failure;
     364          88 :     if (buffer == nullptr)
     365           0 :         return CE_Failure;
     366          88 :     if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0))
     367           0 :         return CE_None;
     368             : 
     369          88 :     m_parent_dataset->m_hint.m_x0 = x0;
     370          88 :     m_parent_dataset->m_hint.m_y0 = y0;
     371          88 :     m_parent_dataset->m_hint.m_sx = sx;
     372          88 :     m_parent_dataset->m_hint.m_sy = sy;
     373          88 :     m_parent_dataset->m_hint.m_overview = m_overview;
     374          88 :     m_parent_dataset->m_hint.m_valid = true;
     375          88 :     ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt,
     376             :                                     nPixelSpace, nLineSpace, psExtraArg);
     377          88 :     m_parent_dataset->m_hint.m_valid = false;
     378             : 
     379          88 :     return ret;
     380             : }
     381             : 
     382           0 : int GDALWMSRasterBand::HasArbitraryOverviews()
     383             : {
     384             :     //    return m_parent_dataset->m_mini_driver_caps.m_has_arb_overviews;
     385           0 :     return 0;  // not implemented yet
     386             : }
     387             : 
     388         187 : int GDALWMSRasterBand::GetOverviewCount()
     389             : {
     390         187 :     return static_cast<int>(m_overviews.size());
     391             : }
     392             : 
     393         276 : GDALRasterBand *GDALWMSRasterBand::GetOverview(int n)
     394             : {
     395         276 :     if ((!m_overviews.empty()) && (static_cast<size_t>(n) < m_overviews.size()))
     396         276 :         return m_overviews[n];
     397             :     else
     398           0 :         return nullptr;
     399             : }
     400             : 
     401        5611 : bool GDALWMSRasterBand::AddOverview(double scale)
     402             : {
     403             :     GDALWMSRasterBand *overview =
     404        5611 :         new GDALWMSRasterBand(m_parent_dataset, nBand, scale);
     405        5611 :     if (overview->GetXSize() == 0 || overview->GetYSize() == 0)
     406             :     {
     407           0 :         delete overview;
     408           0 :         return false;
     409             :     }
     410        5611 :     std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin();
     411       36695 :     for (; it != m_overviews.end(); ++it)
     412             :     {
     413       31084 :         GDALWMSRasterBand *p = *it;
     414       31084 :         if (p->m_scale < scale)
     415           0 :             break;
     416             :     }
     417        5611 :     m_overviews.insert(it, overview);
     418        5611 :     it = m_overviews.begin();
     419       42306 :     for (int i = 0; it != m_overviews.end(); ++it, ++i)
     420             :     {
     421       36695 :         GDALWMSRasterBand *p = *it;
     422       36695 :         p->m_overview = i;
     423             :     }
     424        5611 :     return true;
     425             : }
     426             : 
     427         277 : bool GDALWMSRasterBand::IsBlockInCache(int x, int y)
     428             : {
     429         277 :     bool ret = false;
     430         277 :     GDALRasterBlock *b = TryGetLockedBlockRef(x, y);
     431         277 :     if (b != nullptr)
     432             :     {
     433           0 :         ret = true;
     434           0 :         b->DropLock();
     435             :     }
     436         277 :     return ret;
     437             : }
     438             : 
     439             : // This is the function that calculates the block coordinates for the fetch
     440          56 : CPLErr GDALWMSRasterBand::AskMiniDriverForBlock(WMSHTTPRequest &r, int x, int y)
     441             : {
     442             :     GDALWMSImageRequestInfo iri;
     443             :     GDALWMSTiledImageRequestInfo tiri;
     444             : 
     445          56 :     ComputeRequestInfo(iri, tiri, x, y);
     446         112 :     return m_parent_dataset->m_mini_driver->TiledImageRequest(r, iri, tiri);
     447             : }
     448             : 
     449          56 : void GDALWMSRasterBand::ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
     450             :                                            GDALWMSTiledImageRequestInfo &tiri,
     451             :                                            int x, int y)
     452             : {
     453          56 :     int x0 = std::max(0, x * nBlockXSize);
     454          56 :     int y0 = std::max(0, y * nBlockYSize);
     455          56 :     int x1 = std::max(0, (x + 1) * nBlockXSize);
     456          56 :     int y1 = std::max(0, (y + 1) * nBlockYSize);
     457          56 :     if (m_parent_dataset->m_clamp_requests)
     458             :     {
     459          56 :         x0 = std::min(x0, nRasterXSize);
     460          56 :         y0 = std::min(y0, nRasterYSize);
     461          56 :         x1 = std::min(x1, nRasterXSize);
     462          56 :         y1 = std::min(y1, nRasterYSize);
     463             :     }
     464             : 
     465          56 :     const double rx = (m_parent_dataset->m_data_window.m_x1 -
     466          56 :                        m_parent_dataset->m_data_window.m_x0) /
     467          56 :                       static_cast<double>(nRasterXSize);
     468          56 :     const double ry = (m_parent_dataset->m_data_window.m_y1 -
     469          56 :                        m_parent_dataset->m_data_window.m_y0) /
     470          56 :                       static_cast<double>(nRasterYSize);
     471             :     /* Use different method for x0,y0 and x1,y1 to make sure calculated values
     472             :      * are exact for corner requests */
     473          56 :     iri.m_x0 = x0 * rx + m_parent_dataset->m_data_window.m_x0;
     474          56 :     iri.m_y0 = y0 * ry + m_parent_dataset->m_data_window.m_y0;
     475          56 :     iri.m_x1 = m_parent_dataset->m_data_window.m_x1 - (nRasterXSize - x1) * rx;
     476          56 :     iri.m_y1 = m_parent_dataset->m_data_window.m_y1 - (nRasterYSize - y1) * ry;
     477          56 :     iri.m_sx = x1 - x0;
     478          56 :     iri.m_sy = y1 - y0;
     479             : 
     480          56 :     int level = m_overview + 1;
     481          56 :     tiri.m_x = (m_parent_dataset->m_data_window.m_tx >> level) + x;
     482          56 :     tiri.m_y = (m_parent_dataset->m_data_window.m_ty >> level) + y;
     483          56 :     tiri.m_level = m_parent_dataset->m_data_window.m_tlevel - level;
     484          56 : }
     485             : 
     486             : /************************************************************************/
     487             : /*                      GetMetadataDomainList()                         */
     488             : /************************************************************************/
     489             : 
     490           0 : char **GDALWMSRasterBand::GetMetadataDomainList()
     491             : {
     492           0 :     char **m_list = GDALPamRasterBand::GetMetadataDomainList();
     493           0 :     char **mini_list = m_parent_dataset->m_mini_driver->GetMetadataDomainList();
     494           0 :     if (mini_list != nullptr)
     495             :     {
     496           0 :         m_list = CSLMerge(m_list, mini_list);
     497           0 :         CSLDestroy(mini_list);
     498             :     }
     499           0 :     return m_list;
     500             : }
     501             : 
     502        1022 : const char *GDALWMSRasterBand::GetMetadataItem(const char *pszName,
     503             :                                                const char *pszDomain)
     504             : {
     505        1022 :     if (!m_parent_dataset->m_mini_driver_caps.m_has_getinfo ||
     506          20 :         !(pszDomain != nullptr && EQUAL(pszDomain, "LocationInfo") &&
     507           0 :           (STARTS_WITH_CI(pszName, "Pixel_") ||
     508           0 :            STARTS_WITH_CI(pszName, "GeoPixel_"))))
     509        1022 :         return GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
     510             : 
     511             :     /* ==================================================================== */
     512             :     /*      LocationInfo handling.                                          */
     513             :     /* ==================================================================== */
     514             : 
     515             :     /* -------------------------------------------------------------------- */
     516             :     /*      What pixel are we aiming at?                                    */
     517             :     /* -------------------------------------------------------------------- */
     518             :     int iPixel, iLine;
     519           0 :     if (STARTS_WITH_CI(pszName, "Pixel_"))
     520             :     {
     521           0 :         if (sscanf(pszName + 6, "%d_%d", &iPixel, &iLine) != 2)
     522           0 :             return nullptr;
     523             :     }
     524           0 :     else if (STARTS_WITH_CI(pszName, "GeoPixel_"))
     525             :     {
     526             :         double adfGeoTransform[6];
     527             :         double adfInvGeoTransform[6];
     528             :         double dfGeoX, dfGeoY;
     529             : 
     530             :         {
     531           0 :             dfGeoX = CPLAtof(pszName + 9);
     532           0 :             const char *pszUnderscore = strchr(pszName + 9, '_');
     533           0 :             if (!pszUnderscore)
     534           0 :                 return nullptr;
     535           0 :             dfGeoY = CPLAtof(pszUnderscore + 1);
     536             :         }
     537             : 
     538           0 :         if (m_parent_dataset->GetGeoTransform(adfGeoTransform) != CE_None)
     539           0 :             return nullptr;
     540             : 
     541           0 :         if (!GDALInvGeoTransform(adfGeoTransform, adfInvGeoTransform))
     542           0 :             return nullptr;
     543             : 
     544           0 :         iPixel =
     545           0 :             (int)floor(adfInvGeoTransform[0] + adfInvGeoTransform[1] * dfGeoX +
     546           0 :                        adfInvGeoTransform[2] * dfGeoY);
     547           0 :         iLine =
     548           0 :             (int)floor(adfInvGeoTransform[3] + adfInvGeoTransform[4] * dfGeoX +
     549           0 :                        adfInvGeoTransform[5] * dfGeoY);
     550             : 
     551             :         /* The GetDataset() for the WMS driver is always the main overview
     552             :          * level, so rescale */
     553             :         /* the values if we are an overview */
     554           0 :         if (m_overview >= 0)
     555             :         {
     556           0 :             iPixel = (int)(1.0 * iPixel * GetXSize() /
     557           0 :                            m_parent_dataset->GetRasterBand(1)->GetXSize());
     558           0 :             iLine = (int)(1.0 * iLine * GetYSize() /
     559           0 :                           m_parent_dataset->GetRasterBand(1)->GetYSize());
     560             :         }
     561             :     }
     562             :     else
     563           0 :         return nullptr;
     564             : 
     565           0 :     if (iPixel < 0 || iLine < 0 || iPixel >= GetXSize() || iLine >= GetYSize())
     566           0 :         return nullptr;
     567             : 
     568           0 :     if (nBand != 1)
     569             :     {
     570           0 :         GDALRasterBand *poFirstBand = m_parent_dataset->GetRasterBand(1);
     571           0 :         if (m_overview >= 0)
     572           0 :             poFirstBand = poFirstBand->GetOverview(m_overview);
     573           0 :         if (poFirstBand)
     574           0 :             return poFirstBand->GetMetadataItem(pszName, pszDomain);
     575             :     }
     576             : 
     577             :     GDALWMSImageRequestInfo iri;
     578             :     GDALWMSTiledImageRequestInfo tiri;
     579           0 :     int nBlockXOff = iPixel / nBlockXSize;
     580           0 :     int nBlockYOff = iLine / nBlockYSize;
     581             : 
     582           0 :     ComputeRequestInfo(iri, tiri, nBlockXOff, nBlockYOff);
     583             : 
     584           0 :     CPLString url;
     585           0 :     m_parent_dataset->m_mini_driver->GetTiledImageInfo(
     586           0 :         url, iri, tiri, iPixel % nBlockXSize, iLine % nBlockXSize);
     587             : 
     588           0 :     if (url.empty())
     589           0 :         return nullptr;
     590             : 
     591           0 :     CPLDebug("WMS", "URL = %s", url.c_str());
     592             : 
     593           0 :     if (url == osMetadataItemURL)
     594             :     {
     595             :         // osMetadataItem.c_str() MUST be used, and not osMetadataItem,
     596             :         // otherwise a temporary copy is returned
     597           0 :         return !osMetadataItem.empty() ? osMetadataItem.c_str() : nullptr;
     598             :     }
     599             : 
     600           0 :     osMetadataItemURL = url;
     601             : 
     602             :     // This is OK, CPLHTTPFetch does not touch the options
     603             :     char **papszOptions =
     604           0 :         const_cast<char **>(m_parent_dataset->GetHTTPRequestOpts());
     605           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(url, papszOptions);
     606             : 
     607           0 :     CPLString pszRes;
     608             : 
     609           0 :     if (psResult && psResult->pabyData)
     610           0 :         pszRes = reinterpret_cast<const char *>(psResult->pabyData);
     611           0 :     CPLHTTPDestroyResult(psResult);
     612             : 
     613           0 :     if (pszRes.empty())
     614             :     {
     615           0 :         osMetadataItem = "";
     616           0 :         return nullptr;
     617             :     }
     618             : 
     619           0 :     osMetadataItem = "<LocationInfo>";
     620           0 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     621           0 :     CPLXMLNode *psXML = CPLParseXMLString(pszRes);
     622           0 :     CPLPopErrorHandler();
     623           0 :     if (psXML != nullptr && psXML->eType == CXT_Element)
     624             :     {
     625           0 :         if (strcmp(psXML->pszValue, "?xml") == 0)
     626             :         {
     627           0 :             if (psXML->psNext)
     628             :             {
     629           0 :                 char *pszXML = CPLSerializeXMLTree(psXML->psNext);
     630           0 :                 osMetadataItem += pszXML;
     631           0 :                 CPLFree(pszXML);
     632             :             }
     633             :         }
     634             :         else
     635             :         {
     636           0 :             osMetadataItem += pszRes;
     637           0 :         }
     638             :     }
     639             :     else
     640             :     {
     641           0 :         char *pszEscapedXML = CPLEscapeString(pszRes, -1, CPLES_XML_BUT_QUOTES);
     642           0 :         osMetadataItem += pszEscapedXML;
     643           0 :         CPLFree(pszEscapedXML);
     644             :     }
     645           0 :     if (psXML != nullptr)
     646           0 :         CPLDestroyXMLNode(psXML);
     647             : 
     648           0 :     osMetadataItem += "</LocationInfo>";
     649             : 
     650             :     // osMetadataItem.c_str() MUST be used, and not osMetadataItem,
     651             :     // otherwise a temporary copy is returned
     652           0 :     return osMetadataItem.c_str();
     653             : }
     654             : 
     655          50 : static const int *GetBandMapForExpand(int nSourceBands, int nWmsBands)
     656             : {
     657             :     static const int bandmap1to1[] = {1};
     658             :     static const int bandmap2to1[] = {1};
     659             :     static const int bandmap3to1[] = {1};
     660             :     static const int bandmap4to1[] = {1};
     661             : 
     662             :     static const int bandmap1to2[] = {1, 0};  // 0 == full opaque alpha band
     663             :     static const int bandmap2to2[] = {1, 2};
     664             :     static const int bandmap3to2[] = {1, 0};
     665             :     static const int bandmap4to2[] = {1, 4};
     666             : 
     667             :     static const int bandmap1to3[] = {1, 1, 1};
     668             :     static const int bandmap2to3[] = {1, 1, 1};
     669             :     static const int bandmap3to3[] = {1, 2, 3};
     670             :     static const int bandmap4to3[] = {1, 2, 3};
     671             : 
     672             :     static const int bandmap1to4[] = {1, 1, 1, 0};
     673             :     static const int bandmap2to4[] = {1, 1, 1, 2};
     674             :     static const int bandmap3to4[] = {1, 2, 3, 0};
     675             :     static const int bandmap4to4[] = {1, 2, 3, 4};
     676             : 
     677             :     static const int *const bandmap_selector[4][4] = {
     678             :         {bandmap1to1, bandmap2to1, bandmap3to1, bandmap4to1},
     679             :         {bandmap1to2, bandmap2to2, bandmap3to2, bandmap4to2},
     680             :         {bandmap1to3, bandmap2to3, bandmap3to3, bandmap4to3},
     681             :         {bandmap1to4, bandmap2to4, bandmap3to4, bandmap4to4},
     682             :     };
     683             : 
     684          50 :     if (nSourceBands > 4 || nSourceBands < 1)
     685             :     {
     686           0 :         return nullptr;
     687             :     }
     688          50 :     if (nWmsBands > 4 || nWmsBands < 1)
     689             :     {
     690           0 :         return nullptr;
     691             :     }
     692          50 :     return bandmap_selector[nWmsBands - 1][nSourceBands - 1];
     693             : }
     694             : 
     695          50 : CPLErr GDALWMSRasterBand::ReadBlockFromDataset(GDALDataset *ds, int x, int y,
     696             :                                                int to_buffer_band, void *buffer,
     697             :                                                int advise_read)
     698             : {
     699          50 :     CPLErr ret = CE_None;
     700          50 :     GByte *color_table = nullptr;
     701             :     int i;
     702             : 
     703             :     // CPLDebug("WMS", "ReadBlockFromDataset: to_buffer_band=%d, (x,y)=(%d,
     704             :     // %d)", to_buffer_band, x, y);
     705             : 
     706             :     /* expected size */
     707          50 :     const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) -
     708          50 :                     MIN(MAX(0, x * nBlockXSize), nRasterXSize);
     709          50 :     const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) -
     710          50 :                     MIN(MAX(0, y * nBlockYSize), nRasterYSize);
     711             : 
     712          50 :     int sx = ds->GetRasterXSize();
     713          50 :     int sy = ds->GetRasterYSize();
     714             :     /* Allow bigger than expected so pre-tiled constant size images work on
     715             :      * corners */
     716          50 :     if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy))
     717             :     {
     718           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     719             :                  "GDALWMS: Incorrect size %d x %d of downloaded block, "
     720             :                  "expected %d x %d, max %d x %d.",
     721             :                  sx, sy, esx, esy, nBlockXSize, nBlockYSize);
     722           0 :         ret = CE_Failure;
     723             :     }
     724             : 
     725          50 :     int nDSRasterCount = ds->GetRasterCount();
     726          50 :     if (ret == CE_None)
     727             :     {
     728          50 :         if (nDSRasterCount != m_parent_dataset->nBands)
     729             :         {
     730             :             /* Maybe its an image with color table */
     731          34 :             if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1))
     732             :             {
     733          24 :                 GDALRasterBand *rb = ds->GetRasterBand(1);
     734          24 :                 if (rb->GetRasterDataType() == GDT_Byte)
     735             :                 {
     736          24 :                     GDALColorTable *ct = rb->GetColorTable();
     737          24 :                     if (ct != nullptr)
     738             :                     {
     739          19 :                         if (!advise_read)
     740             :                         {
     741          19 :                             color_table = new GByte[256 * 4];
     742             :                             const int count =
     743          19 :                                 MIN(256, ct->GetColorEntryCount());
     744         796 :                             for (i = 0; i < count; ++i)
     745             :                             {
     746             :                                 GDALColorEntry ce;
     747         777 :                                 ct->GetColorEntryAsRGB(i, &ce);
     748         777 :                                 color_table[i] = static_cast<GByte>(ce.c1);
     749         777 :                                 color_table[i + 256] =
     750         777 :                                     static_cast<GByte>(ce.c2);
     751         777 :                                 color_table[i + 512] =
     752         777 :                                     static_cast<GByte>(ce.c3);
     753         777 :                                 color_table[i + 768] =
     754         777 :                                     static_cast<GByte>(ce.c4);
     755             :                             }
     756             : 
     757        4106 :                             for (i = count; i < 256; ++i)
     758             :                             {
     759        4087 :                                 color_table[i] = 0;
     760        4087 :                                 color_table[i + 256] = 0;
     761        4087 :                                 color_table[i + 512] = 0;
     762        4087 :                                 color_table[i + 768] = 0;
     763             :                             }
     764             :                         }
     765             :                     }
     766           5 :                     else if (m_parent_dataset->nBands <= 4)
     767             :                     {  // Promote single band to fake color table
     768           5 :                         color_table = new GByte[256 * 4];
     769        1285 :                         for (i = 0; i < 256; i++)
     770             :                         {
     771        1280 :                             color_table[i] = static_cast<GByte>(i);
     772        1280 :                             color_table[i + 256] = static_cast<GByte>(i);
     773        1280 :                             color_table[i + 512] = static_cast<GByte>(i);
     774        1280 :                             color_table[i + 768] = 255;  // Transparency
     775             :                         }
     776           5 :                         if (m_parent_dataset->nBands == 2)
     777             :                         {  // Luma-Alpha fixup
     778           0 :                             for (i = 0; i < 256; i++)
     779             :                             {
     780           0 :                                 color_table[i + 256] = 255;
     781             :                             }
     782             :                         }
     783             :                     }
     784             :                 }
     785             :             }
     786             :         }
     787             :     }
     788             : 
     789          50 :     if (!advise_read)
     790             :     {
     791             :         const int *const bandmap =
     792          50 :             GetBandMapForExpand(nDSRasterCount, m_parent_dataset->nBands);
     793         207 :         for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
     794             :         {
     795         157 :             if (ret == CE_None)
     796             :             {
     797         157 :                 void *p = nullptr;
     798         157 :                 GDALRasterBlock *b = nullptr;
     799         157 :                 if ((buffer != nullptr) && (ib == to_buffer_band))
     800             :                 {
     801          30 :                     p = buffer;
     802             :                 }
     803             :                 else
     804             :                 {
     805             :                     GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(
     806         127 :                         m_parent_dataset->GetRasterBand(ib));
     807         127 :                     if (m_overview >= 0)
     808             :                     {
     809             :                         band = static_cast<GDALWMSRasterBand *>(
     810          69 :                             band->GetOverview(m_overview));
     811             :                     }
     812         127 :                     if (!band->IsBlockInCache(x, y))
     813             :                     {
     814         127 :                         b = band->GetLockedBlockRef(x, y, true);
     815         127 :                         if (b != nullptr)
     816             :                         {
     817         127 :                             p = b->GetDataRef();
     818         127 :                             if (p == nullptr)
     819             :                             {
     820           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
     821             :                                          "GDALWMS: GetDataRef returned NULL.");
     822           0 :                                 ret = CE_Failure;
     823             :                             }
     824             :                         }
     825             :                     }
     826             :                     else
     827             :                     {
     828             :                         // CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d)
     829             :                         // already in cache", band->GetBand(), x, y);
     830             :                     }
     831             :                 }
     832             : 
     833         157 :                 if (p != nullptr)
     834             :                 {
     835         157 :                     int pixel_space = GDALGetDataTypeSizeBytes(eDataType);
     836         157 :                     int line_space = pixel_space * nBlockXSize;
     837         157 :                     if (color_table == nullptr)
     838             :                     {
     839          79 :                         if (bandmap == nullptr || bandmap[ib - 1] != 0)
     840             :                         {
     841          78 :                             GDALDataType dt = eDataType;
     842          78 :                             int nSourceBand = ib;
     843          78 :                             if (bandmap != nullptr)
     844             :                             {
     845          78 :                                 nSourceBand = bandmap[ib - 1];
     846             :                             }
     847             :                             // Get the data from the PNG as stored instead of
     848             :                             // converting, if the server asks for that
     849             :                             // TODO: This hack is from #3493 - not sure it
     850             :                             // really belongs here.
     851          78 :                             if ((GDT_Int16 == dt) &&
     852             :                                 (GDT_UInt16 ==
     853           0 :                                  ds->GetRasterBand(ib)->GetRasterDataType()))
     854             :                             {
     855           0 :                                 dt = GDT_UInt16;
     856             :                             }
     857             : 
     858          78 :                             if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy,
     859             :                                              dt, 1, &nSourceBand, pixel_space,
     860          78 :                                              line_space, 0, nullptr) != CE_None)
     861             :                             {
     862           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
     863             :                                          "GDALWMS: RasterIO failed on "
     864             :                                          "downloaded block.");
     865           0 :                                 ret = CE_Failure;
     866          78 :                             }
     867             :                         }
     868             :                         else  // if( bandmap != nullptr && bandmap[ib - 1] == 0
     869             :                               // )
     870             :                         {  // parent expects 4 bands but file has fewer count so
     871             :                             // generate a all "opaque" 4th band
     872           1 :                             GByte *byte_buffer = reinterpret_cast<GByte *>(p);
     873         129 :                             for (int l_y = 0; l_y < sy; ++l_y)
     874             :                             {
     875       16512 :                                 for (int l_x = 0; l_x < sx; ++l_x)
     876             :                                 {
     877       16384 :                                     const int offset = l_x + l_y * line_space;
     878       16384 :                                     byte_buffer[offset] =
     879             :                                         255;  // fill with opaque
     880             :                                 }
     881             :                             }
     882             :                         }
     883             :                     }
     884          78 :                     else if (ib <= 4)
     885             :                     {
     886          78 :                         if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy,
     887             :                                          eDataType, 1, nullptr, pixel_space,
     888          78 :                                          line_space, 0, nullptr) != CE_None)
     889             :                         {
     890           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     891             :                                      "GDALWMS: RasterIO failed on downloaded "
     892             :                                      "block.");
     893           0 :                             ret = CE_Failure;
     894             :                         }
     895             : 
     896          78 :                         if (ret == CE_None)
     897             :                         {
     898          78 :                             GByte *band_color_table =
     899          78 :                                 color_table + 256 * (ib - 1);
     900          78 :                             GByte *byte_buffer = reinterpret_cast<GByte *>(p);
     901       20558 :                             for (int l_y = 0; l_y < sy; ++l_y)
     902             :                             {
     903     5918720 :                                 for (int l_x = 0; l_x < sx; ++l_x)
     904             :                                 {
     905     5898240 :                                     const int offset = l_x + l_y * line_space;
     906     5898240 :                                     byte_buffer[offset] =
     907     5898240 :                                         band_color_table[byte_buffer[offset]];
     908             :                                 }
     909             :                             }
     910             :                         }
     911             :                     }
     912             :                     else
     913             :                     {
     914           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     915             :                                  "GDALWMS: Color table supports at most 4 "
     916             :                                  "components.");
     917           0 :                         ret = CE_Failure;
     918             :                     }
     919             :                 }
     920         157 :                 if (b != nullptr)
     921             :                 {
     922         127 :                     b->DropLock();
     923             :                 }
     924             :             }
     925             :         }
     926             :     }
     927          50 :     GDALClose(ds);
     928             : 
     929          50 :     if (color_table != nullptr)
     930             :     {
     931          24 :         delete[] color_table;
     932             :     }
     933             : 
     934          50 :     return ret;
     935             : }
     936             : 
     937          38 : CPLErr GDALWMSRasterBand::ReadBlockFromFile(const CPLString &soFileName, int x,
     938             :                                             int y, int to_buffer_band,
     939             :                                             void *buffer, int advise_read)
     940             : {
     941          38 :     GDALDataset *ds = GDALDataset::FromHandle(GDALOpenEx(
     942             :         soFileName, GDAL_OF_RASTER | GDAL_OF_READONLY | GDAL_OF_VERBOSE_ERROR,
     943          38 :         nullptr, m_parent_dataset->m_tileOO, nullptr));
     944          38 :     if (ds == nullptr)
     945             :     {
     946           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     947             :                  "GDALWMS: Unable to open downloaded block.");
     948           0 :         return CE_Failure;
     949             :     }
     950             : 
     951          38 :     return ReadBlockFromDataset(ds, x, y, to_buffer_band, buffer, advise_read);
     952             : }
     953             : 
     954          14 : CPLErr GDALWMSRasterBand::ReadBlockFromCache(const char *pszKey, int x, int y,
     955             :                                              int to_buffer_band, void *buffer,
     956             :                                              int advise_read)
     957             : {
     958          14 :     GDALWMSCache *cache = m_parent_dataset->m_cache;
     959          14 :     if (nullptr == cache)
     960             :     {
     961           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     962             :                  "GDALWMS: Unable to open downloaded block.");
     963           0 :         return CE_Failure;
     964             :     }
     965          14 :     GDALDataset *ds = cache->GetDataset(pszKey, m_parent_dataset->m_tileOO);
     966          14 :     if (ds == nullptr)
     967             :     {
     968           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     969             :                  "GDALWMS: Unable to open downloaded block.");
     970           2 :         return CE_Failure;
     971             :     }
     972             : 
     973          12 :     return ReadBlockFromDataset(ds, x, y, to_buffer_band, buffer, advise_read);
     974             : }
     975             : 
     976           2 : CPLErr GDALWMSRasterBand::EmptyBlock(int x, int y, int to_buffer_band,
     977             :                                      void *buffer)
     978             : {
     979           2 :     CPLErr ret = CE_None;
     980             : 
     981          10 :     for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
     982             :     {
     983           8 :         if (ret == CE_None)
     984             :         {
     985           8 :             void *p = nullptr;
     986           8 :             GDALRasterBlock *b = nullptr;
     987             :             GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(
     988           8 :                 m_parent_dataset->GetRasterBand(ib));
     989           8 :             if (m_overview >= 0)
     990             :                 band = static_cast<GDALWMSRasterBand *>(
     991           0 :                     band->GetOverview(m_overview));
     992           8 :             if ((buffer != nullptr) && (ib == to_buffer_band))
     993             :             {
     994           2 :                 p = buffer;
     995             :             }
     996             :             else
     997             :             {
     998           6 :                 if (!band->IsBlockInCache(x, y))
     999             :                 {
    1000           6 :                     b = band->GetLockedBlockRef(x, y, true);
    1001           6 :                     if (b != nullptr)
    1002             :                     {
    1003           6 :                         p = b->GetDataRef();
    1004           6 :                         if (p == nullptr)
    1005             :                         {
    1006           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1007             :                                      "GDALWMS: GetDataRef returned NULL.");
    1008           0 :                             ret = CE_Failure;
    1009             :                         }
    1010             :                     }
    1011             :                 }
    1012             :             }
    1013           8 :             if (p != nullptr)
    1014             :             {
    1015             :                 int hasNDV;
    1016           8 :                 double valNDV = band->GetNoDataValue(&hasNDV);
    1017           8 :                 if (!hasNDV)
    1018           8 :                     valNDV = 0;
    1019           8 :                 GDALCopyWords(&valNDV, GDT_Float64, 0, p, eDataType,
    1020             :                               GDALGetDataTypeSizeBytes(eDataType),
    1021           8 :                               nBlockXSize * nBlockYSize);
    1022             :             }
    1023           8 :             if (b != nullptr)
    1024             :             {
    1025           6 :                 b->DropLock();
    1026             :             }
    1027             :         }
    1028             :     }
    1029             : 
    1030           2 :     return ret;
    1031             : }
    1032             : 
    1033           0 : CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name)
    1034             : {
    1035           0 :     CPLErr ret = CE_None;
    1036           0 :     int reported_errors_count = 0;
    1037             : 
    1038           0 :     CPLXMLNode *orig_root = CPLParseXMLFile(file_name);
    1039           0 :     CPLXMLNode *root = orig_root;
    1040           0 :     if (root != nullptr)
    1041             :     {
    1042           0 :         root = CPLGetXMLNode(root, "=ServiceExceptionReport");
    1043             :     }
    1044           0 :     if (root != nullptr)
    1045             :     {
    1046           0 :         CPLXMLNode *n = CPLGetXMLNode(root, "ServiceException");
    1047           0 :         while (n != nullptr)
    1048             :         {
    1049           0 :             const char *exception = CPLGetXMLValue(n, "=ServiceException", "");
    1050             :             const char *exception_code =
    1051           0 :                 CPLGetXMLValue(n, "=ServiceException.code", "");
    1052           0 :             if (exception[0] != '\0')
    1053             :             {
    1054           0 :                 if (exception_code[0] != '\0')
    1055             :                 {
    1056           0 :                     CPLError(
    1057             :                         CE_Failure, CPLE_AppDefined,
    1058             :                         "GDALWMS: The server returned exception code '%s': %s",
    1059             :                         exception_code, exception);
    1060           0 :                     ++reported_errors_count;
    1061             :                 }
    1062             :                 else
    1063             :                 {
    1064           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1065             :                              "GDALWMS: The server returned exception: %s",
    1066             :                              exception);
    1067           0 :                     ++reported_errors_count;
    1068             :                 }
    1069             :             }
    1070           0 :             else if (exception_code[0] != '\0')
    1071             :             {
    1072           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1073             :                          "GDALWMS: The server returned exception code '%s'.",
    1074             :                          exception_code);
    1075           0 :                 ++reported_errors_count;
    1076             :             }
    1077             : 
    1078           0 :             n = n->psNext;
    1079           0 :             if (n != nullptr)
    1080             :             {
    1081           0 :                 n = CPLGetXMLNode(n, "=ServiceException");
    1082             :             }
    1083             :         }
    1084             :     }
    1085             :     else
    1086             :     {
    1087           0 :         ret = CE_Failure;
    1088             :     }
    1089           0 :     if (orig_root != nullptr)
    1090             :     {
    1091           0 :         CPLDestroyXMLNode(orig_root);
    1092             :     }
    1093             : 
    1094           0 :     if (reported_errors_count == 0)
    1095             :     {
    1096           0 :         ret = CE_Failure;
    1097             :     }
    1098             : 
    1099           0 :     return ret;
    1100             : }
    1101             : 
    1102           0 : CPLErr GDALWMSRasterBand::AdviseRead(int nXOff, int nYOff, int nXSize,
    1103             :                                      int nYSize, int nBufXSize, int nBufYSize,
    1104             :                                      GDALDataType eDT, char **papszOptions)
    1105             : {
    1106             :     //    printf("AdviseRead(%d, %d, %d, %d)\n", nXOff, nYOff, nXSize, nYSize);
    1107           0 :     if (m_parent_dataset->m_offline_mode ||
    1108           0 :         !m_parent_dataset->m_use_advise_read)
    1109           0 :         return CE_None;
    1110           0 :     if (m_parent_dataset->m_cache == nullptr)
    1111           0 :         return CE_Failure;
    1112             : 
    1113             :     /* ==================================================================== */
    1114             :     /*      Do we have overviews that would be appropriate to satisfy       */
    1115             :     /*      this request?                                                   */
    1116             :     /* ==================================================================== */
    1117           0 :     if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
    1118             :     {
    1119           0 :         const int nOverview = GDALBandGetBestOverviewLevel2(
    1120             :             this, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, nullptr);
    1121           0 :         if (nOverview >= 0)
    1122             :         {
    1123           0 :             GDALRasterBand *poOverviewBand = GetOverview(nOverview);
    1124           0 :             if (poOverviewBand == nullptr)
    1125           0 :                 return CE_Failure;
    1126             : 
    1127           0 :             return poOverviewBand->AdviseRead(nXOff, nYOff, nXSize, nYSize,
    1128             :                                               nBufXSize, nBufYSize, eDT,
    1129           0 :                                               papszOptions);
    1130             :         }
    1131             :     }
    1132             : 
    1133           0 :     int bx0 = nXOff / nBlockXSize;
    1134           0 :     int by0 = nYOff / nBlockYSize;
    1135           0 :     int bx1 = (nXOff + nXSize - 1) / nBlockXSize;
    1136           0 :     int by1 = (nYOff + nYSize - 1) / nBlockYSize;
    1137             : 
    1138             :     // Avoid downloading a insane number of tiles
    1139           0 :     const int MAX_TILES = 1000;  // arbitrary number
    1140           0 :     if ((bx1 - bx0 + 1) > MAX_TILES / (by1 - by0 + 1))
    1141             :     {
    1142           0 :         CPLDebug("WMS", "Too many tiles for AdviseRead()");
    1143           0 :         return CE_Failure;
    1144             :     }
    1145             : 
    1146           0 :     if (m_nAdviseReadBX0 == bx0 && m_nAdviseReadBY0 == by0 &&
    1147           0 :         m_nAdviseReadBX1 == bx1 && m_nAdviseReadBY1 == by1)
    1148             :     {
    1149           0 :         return CE_None;
    1150             :     }
    1151           0 :     m_nAdviseReadBX0 = bx0;
    1152           0 :     m_nAdviseReadBY0 = by0;
    1153           0 :     m_nAdviseReadBX1 = bx1;
    1154           0 :     m_nAdviseReadBY1 = by1;
    1155             : 
    1156           0 :     return ReadBlocks(0, 0, nullptr, bx0, by0, bx1, by1, 1);
    1157             : }
    1158             : 
    1159         399 : GDALColorInterp GDALWMSRasterBand::GetColorInterpretation()
    1160             : {
    1161         399 :     return m_color_interp;
    1162             : }
    1163             : 
    1164           9 : CPLErr GDALWMSRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
    1165             : {
    1166           9 :     m_color_interp = eNewInterp;
    1167           9 :     return CE_None;
    1168             : }
    1169             : 
    1170             : // Utility function, returns a value from a vector corresponding to the band
    1171             : // index or the first entry
    1172           0 : static double getBandValue(const std::vector<double> &v, size_t idx)
    1173             : {
    1174           0 :     idx--;
    1175           0 :     if (v.size() > idx)
    1176           0 :         return v[idx];
    1177           0 :     return v[0];
    1178             : }
    1179             : 
    1180         469 : double GDALWMSRasterBand::GetNoDataValue(int *pbSuccess)
    1181             : {
    1182         469 :     std::vector<double> &v = m_parent_dataset->vNoData;
    1183         469 :     if (v.empty())
    1184         469 :         return GDALPamRasterBand::GetNoDataValue(pbSuccess);
    1185           0 :     if (pbSuccess)
    1186           0 :         *pbSuccess = TRUE;
    1187           0 :     return getBandValue(v, nBand);
    1188             : }
    1189             : 
    1190           0 : double GDALWMSRasterBand::GetMinimum(int *pbSuccess)
    1191             : {
    1192           0 :     std::vector<double> &v = m_parent_dataset->vMin;
    1193           0 :     if (v.empty())
    1194           0 :         return GDALPamRasterBand::GetMinimum(pbSuccess);
    1195           0 :     if (pbSuccess)
    1196           0 :         *pbSuccess = TRUE;
    1197           0 :     return getBandValue(v, nBand);
    1198             : }
    1199             : 
    1200           0 : double GDALWMSRasterBand::GetMaximum(int *pbSuccess)
    1201             : {
    1202           0 :     std::vector<double> &v = m_parent_dataset->vMax;
    1203           0 :     if (v.empty())
    1204           0 :         return GDALPamRasterBand::GetMaximum(pbSuccess);
    1205           0 :     if (pbSuccess)
    1206           0 :         *pbSuccess = TRUE;
    1207           0 :     return getBandValue(v, nBand);
    1208             : }
    1209             : 
    1210         316 : GDALColorTable *GDALWMSRasterBand::GetColorTable()
    1211             : {
    1212         316 :     return m_parent_dataset->m_poColorTable;
    1213             : }

Generated by: LCOV version 1.14