LCOV - code coverage report
Current view: top level - frmts/wms - gdalwmsrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 352 580 60.7 %
Date: 2025-07-09 17:50:03 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        6959 : GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band,
      21        6959 :                                      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        6959 :       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        6959 :     if (scale == 1.0)
      32        1336 :         poDS = parent_dataset;
      33             :     else
      34        5623 :         poDS = nullptr;
      35        6959 :     if (parent_dataset->m_mini_driver_caps.m_overview_dim_computation_method ==
      36             :         OVERVIEW_ROUNDED)
      37             :     {
      38        6887 :         nRasterXSize = static_cast<int>(
      39        6887 :             m_parent_dataset->m_data_window.m_sx * scale + 0.5);
      40        6887 :         nRasterYSize = static_cast<int>(
      41        6887 :             m_parent_dataset->m_data_window.m_sy * scale + 0.5);
      42             :     }
      43             :     else
      44             :     {
      45          72 :         nRasterXSize =
      46          72 :             static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale);
      47          72 :         nRasterYSize =
      48          72 :             static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale);
      49             :     }
      50        6959 :     nBand = band;
      51        6959 :     eDataType = m_parent_dataset->m_data_type;
      52        6959 :     nBlockXSize = m_parent_dataset->m_block_size_x;
      53        6959 :     nBlockYSize = m_parent_dataset->m_block_size_y;
      54        6959 : }
      55             : 
      56       20877 : GDALWMSRasterBand::~GDALWMSRasterBand()
      57             : {
      58       12582 :     while (!m_overviews.empty())
      59             :     {
      60        5623 :         delete m_overviews.back();
      61        5623 :         m_overviews.pop_back();
      62             :     }
      63       13918 : }
      64             : 
      65             : // Request for x, y but all blocks between bx0-bx1 and by0-by1 should be read
      66          39 : CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0,
      67             :                                      int by0, int bx1, int by1, int advise_read)
      68             : {
      69          39 :     CPLErr ret = CE_None;
      70             : 
      71             :     // Get a vector of requests large enough for this call
      72          39 :     std::vector<WMSHTTPRequest> requests(static_cast<size_t>(bx1 - bx0 + 1) *
      73          39 :                                          (by1 - by0 + 1));
      74             : 
      75          39 :     size_t count = 0;  // How many requests are valid
      76          39 :     GDALWMSCache *cache = m_parent_dataset->m_cache;
      77          39 :     int offline = m_parent_dataset->m_offline_mode;
      78          39 :     const char *const *options = m_parent_dataset->GetHTTPRequestOpts();
      79             : 
      80          83 :     for (int iy = by0; iy <= by1; ++iy)
      81             :     {
      82         103 :         for (int ix = bx0; ix <= bx1; ++ix)
      83             :         {
      84          59 :             WMSHTTPRequest &request = requests[count];
      85          59 :             request.x = ix;
      86          59 :             request.y = iy;
      87          59 :             bool need_this_block = false;
      88          59 :             if (!advise_read)
      89             :             {
      90         248 :                 for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
      91             :                 {
      92         189 :                     if ((ix == x) && (iy == y) && (ib == nBand))
      93             :                     {
      94          39 :                         need_this_block = true;
      95             :                     }
      96             :                     else
      97             :                     {
      98             :                         GDALWMSRasterBand *band =
      99             :                             static_cast<GDALWMSRasterBand *>(
     100         150 :                                 m_parent_dataset->GetRasterBand(ib));
     101         150 :                         if (m_overview >= 0)
     102             :                             band = static_cast<GDALWMSRasterBand *>(
     103          75 :                                 band->GetOverview(m_overview));
     104         150 :                         if (!band->IsBlockInCache(ix, iy))
     105         150 :                             need_this_block = true;
     106             :                     }
     107             :                 }
     108             :             }
     109             :             else
     110             :             {
     111           0 :                 need_this_block = true;
     112             :             }
     113             : 
     114          59 :             void *p = ((ix == x) && (iy == y)) ? buffer : nullptr;
     115          59 :             if (need_this_block)
     116             :             {
     117          59 :                 ret = AskMiniDriverForBlock(request, ix, iy);
     118          59 :                 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          59 :                 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          59 :                 if (ret == CE_None && cache != nullptr)
     139             :                 {
     140          36 :                     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          59 :             if (need_this_block)
     159             :             {
     160          47 :                 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          47 :                     request.options = options;
     175          47 :                     WMSHTTPInitializeRequest(&request);
     176          47 :                     count++;
     177             :                 }
     178             :             }
     179             :         }
     180             :     }
     181             : 
     182             :     // Fetch all the requests, OK to call with count of 0
     183          39 :     if (WMSHTTPFetchMulti(count ? &requests[0] : nullptr,
     184          39 :                           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          86 :     for (size_t i = 0; i < count; ++i)
     192             :     {
     193          47 :         WMSHTTPRequest &request = requests[i];
     194          47 :         void *p = ((request.x == x) && (request.y == y)) ? buffer : nullptr;
     195          47 :         if (ret == CE_None)
     196             :         {
     197          53 :             int success = (request.nStatus == 200) ||
     198           6 :                           (!request.Range.empty() && request.nStatus == 206);
     199          47 :             if (success && (request.pabyData != nullptr) &&
     200          41 :                 (request.nDataLen > 0))
     201             :             {
     202             :                 CPLString file_name(
     203          82 :                     BufferToVSIFile(request.pabyData, request.nDataLen));
     204          41 :                 if (!file_name.empty())
     205             :                 {
     206             :                     /* check for error xml */
     207          41 :                     if (request.nDataLen >= 20)
     208             :                     {
     209          41 :                         const char *download_data =
     210             :                             reinterpret_cast<char *>(request.pabyData);
     211          41 :                         if (STARTS_WITH_CI(download_data, "<?xml ") ||
     212          41 :                             STARTS_WITH_CI(download_data, "<!DOCTYPE ") ||
     213          41 :                             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          41 :                     if (ret == CE_None)
     225             :                     {
     226          41 :                         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          41 :                             ret = ReadBlockFromFile(file_name, request.x,
     235             :                                                     request.y, nBand, p,
     236             :                                                     advise_read);
     237          41 :                             if (ret == CE_None)
     238             :                             {
     239          41 :                                 if (cache != nullptr)
     240          22 :                                     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          41 :                     VSIUnlink(file_name);
     259          41 :                 }
     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 https://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          78 :     return ret;
     310             : }
     311             : 
     312          39 : CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer)
     313             : {
     314          39 :     int bx0 = x;
     315          39 :     int by0 = y;
     316          39 :     int bx1 = x;
     317          39 :     int by1 = y;
     318             : 
     319          39 :     bool bCancelHint = false;
     320          39 :     if ((m_parent_dataset->m_hint.m_valid) &&
     321          39 :         (m_parent_dataset->m_hint.m_overview == m_overview))
     322             :     {
     323          39 :         int tbx0 = m_parent_dataset->m_hint.m_x0 / nBlockXSize;
     324          39 :         int tby0 = m_parent_dataset->m_hint.m_y0 / nBlockYSize;
     325          39 :         int tbx1 = (m_parent_dataset->m_hint.m_x0 +
     326          39 :                     m_parent_dataset->m_hint.m_sx - 1) /
     327          39 :                    nBlockXSize;
     328          39 :         int tby1 = (m_parent_dataset->m_hint.m_y0 +
     329          39 :                     m_parent_dataset->m_hint.m_sy - 1) /
     330          39 :                    nBlockYSize;
     331          39 :         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          39 :             bx0 = std::max(x - 15, tbx0);
     336          39 :             by0 = std::max(y - 15, tby0);
     337          39 :             bx1 = std::min(x + 15, tbx1);
     338          39 :             by1 = std::min(y + 15, tby1);
     339          39 :             bCancelHint =
     340          39 :                 (bx0 == tbx0 && by0 == tby0 && bx1 == tbx1 && by1 == tby1);
     341             :         }
     342             :     }
     343             : 
     344          39 :     CPLErr eErr = ReadBlocks(x, y, buffer, bx0, by0, bx1, by1, 0);
     345             : 
     346          39 :     if (bCancelHint)
     347             :     {
     348          39 :         m_parent_dataset->m_hint.m_valid = false;
     349             :     }
     350             : 
     351          39 :     return eErr;
     352             : }
     353             : 
     354         100 : 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         100 :     if (rw != GF_Read)
     363           0 :         return CE_Failure;
     364         100 :     if (buffer == nullptr)
     365           0 :         return CE_Failure;
     366         100 :     if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0))
     367           0 :         return CE_None;
     368             : 
     369         100 :     m_parent_dataset->m_hint.m_x0 = x0;
     370         100 :     m_parent_dataset->m_hint.m_y0 = y0;
     371         100 :     m_parent_dataset->m_hint.m_sx = sx;
     372         100 :     m_parent_dataset->m_hint.m_sy = sy;
     373         100 :     m_parent_dataset->m_hint.m_overview = m_overview;
     374         100 :     m_parent_dataset->m_hint.m_valid = true;
     375         100 :     ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt,
     376             :                                     nPixelSpace, nLineSpace, psExtraArg);
     377         100 :     m_parent_dataset->m_hint.m_valid = false;
     378             : 
     379         100 :     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         188 : int GDALWMSRasterBand::GetOverviewCount()
     389             : {
     390         188 :     return static_cast<int>(m_overviews.size());
     391             : }
     392             : 
     393         293 : GDALRasterBand *GDALWMSRasterBand::GetOverview(int n)
     394             : {
     395         293 :     if ((!m_overviews.empty()) && (static_cast<size_t>(n) < m_overviews.size()))
     396         293 :         return m_overviews[n];
     397             :     else
     398           0 :         return nullptr;
     399             : }
     400             : 
     401        5623 : bool GDALWMSRasterBand::AddOverview(double scale)
     402             : {
     403             :     GDALWMSRasterBand *overview =
     404        5623 :         new GDALWMSRasterBand(m_parent_dataset, nBand, scale);
     405        5623 :     if (overview->GetXSize() == 0 || overview->GetYSize() == 0)
     406             :     {
     407           0 :         delete overview;
     408           0 :         return false;
     409             :     }
     410        5623 :     std::vector<GDALWMSRasterBand *>::iterator it = m_overviews.begin();
     411       36761 :     for (; it != m_overviews.end(); ++it)
     412             :     {
     413       31138 :         GDALWMSRasterBand *p = *it;
     414       31138 :         if (p->m_scale < scale)
     415           0 :             break;
     416             :     }
     417        5623 :     m_overviews.insert(it, overview);
     418        5623 :     it = m_overviews.begin();
     419       42384 :     for (int i = 0; it != m_overviews.end(); ++it, ++i)
     420             :     {
     421       36761 :         GDALWMSRasterBand *p = *it;
     422       36761 :         p->m_overview = i;
     423             :     }
     424        5623 :     return true;
     425             : }
     426             : 
     427         289 : bool GDALWMSRasterBand::IsBlockInCache(int x, int y)
     428             : {
     429         289 :     bool ret = false;
     430         289 :     GDALRasterBlock *b = TryGetLockedBlockRef(x, y);
     431         289 :     if (b != nullptr)
     432             :     {
     433           0 :         ret = true;
     434           0 :         b->DropLock();
     435             :     }
     436         289 :     return ret;
     437             : }
     438             : 
     439             : // This is the function that calculates the block coordinates for the fetch
     440          59 : CPLErr GDALWMSRasterBand::AskMiniDriverForBlock(WMSHTTPRequest &r, int x, int y)
     441             : {
     442          59 :     GDALWMSImageRequestInfo iri;
     443          59 :     GDALWMSTiledImageRequestInfo tiri;
     444             : 
     445          59 :     ComputeRequestInfo(iri, tiri, x, y);
     446         118 :     return m_parent_dataset->m_mini_driver->TiledImageRequest(r, iri, tiri);
     447             : }
     448             : 
     449          59 : void GDALWMSRasterBand::ComputeRequestInfo(GDALWMSImageRequestInfo &iri,
     450             :                                            GDALWMSTiledImageRequestInfo &tiri,
     451             :                                            int x, int y)
     452             : {
     453          59 :     int x0 = std::max(0, x * nBlockXSize);
     454          59 :     int y0 = std::max(0, y * nBlockYSize);
     455          59 :     int x1 = std::max(0, (x + 1) * nBlockXSize);
     456          59 :     int y1 = std::max(0, (y + 1) * nBlockYSize);
     457          59 :     if (m_parent_dataset->m_clamp_requests)
     458             :     {
     459          59 :         x0 = std::min(x0, nRasterXSize);
     460          59 :         y0 = std::min(y0, nRasterYSize);
     461          59 :         x1 = std::min(x1, nRasterXSize);
     462          59 :         y1 = std::min(y1, nRasterYSize);
     463             :     }
     464             : 
     465          59 :     const double rx = (m_parent_dataset->m_data_window.m_x1 -
     466          59 :                        m_parent_dataset->m_data_window.m_x0) /
     467          59 :                       static_cast<double>(nRasterXSize);
     468          59 :     const double ry = (m_parent_dataset->m_data_window.m_y1 -
     469          59 :                        m_parent_dataset->m_data_window.m_y0) /
     470          59 :                       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          59 :     iri.m_x0 = x0 * rx + m_parent_dataset->m_data_window.m_x0;
     474          59 :     iri.m_y0 = y0 * ry + m_parent_dataset->m_data_window.m_y0;
     475          59 :     iri.m_x1 = m_parent_dataset->m_data_window.m_x1 - (nRasterXSize - x1) * rx;
     476          59 :     iri.m_y1 = m_parent_dataset->m_data_window.m_y1 - (nRasterYSize - y1) * ry;
     477          59 :     iri.m_sx = x1 - x0;
     478          59 :     iri.m_sy = y1 - y0;
     479             : 
     480          59 :     int level = m_overview + 1;
     481          59 :     tiri.m_x = (m_parent_dataset->m_data_window.m_tx >> level) + x;
     482          59 :     tiri.m_y = (m_parent_dataset->m_data_window.m_ty >> level) + y;
     483          59 :     tiri.m_level = m_parent_dataset->m_data_window.m_tlevel - level;
     484          59 : }
     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        1025 : const char *GDALWMSRasterBand::GetMetadataItem(const char *pszName,
     503             :                                                const char *pszDomain)
     504             : {
     505        1025 :     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        1025 :         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           0 :         GDALGeoTransform gt, invGT;
     527             :         double dfGeoX, dfGeoY;
     528             : 
     529             :         {
     530           0 :             dfGeoX = CPLAtof(pszName + 9);
     531           0 :             const char *pszUnderscore = strchr(pszName + 9, '_');
     532           0 :             if (!pszUnderscore)
     533           0 :                 return nullptr;
     534           0 :             dfGeoY = CPLAtof(pszUnderscore + 1);
     535             :         }
     536             : 
     537           0 :         if (m_parent_dataset->GetGeoTransform(gt) != CE_None)
     538           0 :             return nullptr;
     539             : 
     540           0 :         if (!GDALInvGeoTransform(gt.data(), invGT.data()))
     541           0 :             return nullptr;
     542             : 
     543           0 :         iPixel = static_cast<int>(
     544           0 :             floor(invGT[0] + invGT[1] * dfGeoX + invGT[2] * dfGeoY));
     545           0 :         iLine = static_cast<int>(
     546           0 :             floor(invGT[3] + invGT[4] * dfGeoX + invGT[5] * dfGeoY));
     547             : 
     548             :         /* The GetDataset() for the WMS driver is always the main overview
     549             :          * level, so rescale */
     550             :         /* the values if we are an overview */
     551           0 :         if (m_overview >= 0)
     552             :         {
     553           0 :             iPixel = static_cast<int>(
     554           0 :                 1.0 * iPixel * GetXSize() /
     555           0 :                 m_parent_dataset->GetRasterBand(1)->GetXSize());
     556           0 :             iLine = static_cast<int>(
     557           0 :                 1.0 * iLine * GetYSize() /
     558           0 :                 m_parent_dataset->GetRasterBand(1)->GetYSize());
     559             :         }
     560             :     }
     561             :     else
     562           0 :         return nullptr;
     563             : 
     564           0 :     if (iPixel < 0 || iLine < 0 || iPixel >= GetXSize() || iLine >= GetYSize())
     565           0 :         return nullptr;
     566             : 
     567           0 :     if (nBand != 1)
     568             :     {
     569           0 :         GDALRasterBand *poFirstBand = m_parent_dataset->GetRasterBand(1);
     570           0 :         if (m_overview >= 0)
     571           0 :             poFirstBand = poFirstBand->GetOverview(m_overview);
     572           0 :         if (poFirstBand)
     573           0 :             return poFirstBand->GetMetadataItem(pszName, pszDomain);
     574             :     }
     575             : 
     576           0 :     GDALWMSImageRequestInfo iri;
     577           0 :     GDALWMSTiledImageRequestInfo tiri;
     578           0 :     int nBlockXOff = iPixel / nBlockXSize;
     579           0 :     int nBlockYOff = iLine / nBlockYSize;
     580             : 
     581           0 :     ComputeRequestInfo(iri, tiri, nBlockXOff, nBlockYOff);
     582             : 
     583           0 :     CPLString url;
     584           0 :     m_parent_dataset->m_mini_driver->GetTiledImageInfo(
     585           0 :         url, iri, tiri, iPixel % nBlockXSize, iLine % nBlockXSize);
     586             : 
     587           0 :     if (url.empty())
     588           0 :         return nullptr;
     589             : 
     590           0 :     CPLDebug("WMS", "URL = %s", url.c_str());
     591             : 
     592           0 :     if (url == osMetadataItemURL)
     593             :     {
     594             :         // osMetadataItem.c_str() MUST be used, and not osMetadataItem,
     595             :         // otherwise a temporary copy is returned
     596           0 :         return !osMetadataItem.empty() ? osMetadataItem.c_str() : nullptr;
     597             :     }
     598             : 
     599           0 :     osMetadataItemURL = url;
     600             : 
     601             :     // This is OK, CPLHTTPFetch does not touch the options
     602             :     char **papszOptions =
     603           0 :         const_cast<char **>(m_parent_dataset->GetHTTPRequestOpts());
     604           0 :     CPLHTTPResult *psResult = CPLHTTPFetch(url, papszOptions);
     605             : 
     606           0 :     CPLString pszRes;
     607             : 
     608           0 :     if (psResult && psResult->pabyData)
     609           0 :         pszRes = reinterpret_cast<const char *>(psResult->pabyData);
     610           0 :     CPLHTTPDestroyResult(psResult);
     611             : 
     612           0 :     if (pszRes.empty())
     613             :     {
     614           0 :         osMetadataItem = "";
     615           0 :         return nullptr;
     616             :     }
     617             : 
     618           0 :     osMetadataItem = "<LocationInfo>";
     619           0 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     620           0 :     CPLXMLNode *psXML = CPLParseXMLString(pszRes);
     621           0 :     CPLPopErrorHandler();
     622           0 :     if (psXML != nullptr && psXML->eType == CXT_Element)
     623             :     {
     624           0 :         if (strcmp(psXML->pszValue, "?xml") == 0)
     625             :         {
     626           0 :             if (psXML->psNext)
     627             :             {
     628           0 :                 char *pszXML = CPLSerializeXMLTree(psXML->psNext);
     629           0 :                 osMetadataItem += pszXML;
     630           0 :                 CPLFree(pszXML);
     631             :             }
     632             :         }
     633             :         else
     634             :         {
     635           0 :             osMetadataItem += pszRes;
     636           0 :         }
     637             :     }
     638             :     else
     639             :     {
     640           0 :         char *pszEscapedXML = CPLEscapeString(pszRes, -1, CPLES_XML_BUT_QUOTES);
     641           0 :         osMetadataItem += pszEscapedXML;
     642           0 :         CPLFree(pszEscapedXML);
     643             :     }
     644           0 :     if (psXML != nullptr)
     645           0 :         CPLDestroyXMLNode(psXML);
     646             : 
     647           0 :     osMetadataItem += "</LocationInfo>";
     648             : 
     649             :     // osMetadataItem.c_str() MUST be used, and not osMetadataItem,
     650             :     // otherwise a temporary copy is returned
     651           0 :     return osMetadataItem.c_str();
     652             : }
     653             : 
     654          53 : static const int *GetBandMapForExpand(int nSourceBands, int nWmsBands)
     655             : {
     656             :     static const int bandmap1to1[] = {1};
     657             :     static const int bandmap2to1[] = {1};
     658             :     static const int bandmap3to1[] = {1};
     659             :     static const int bandmap4to1[] = {1};
     660             : 
     661             :     static const int bandmap1to2[] = {1, 0};  // 0 == full opaque alpha band
     662             :     static const int bandmap2to2[] = {1, 2};
     663             :     static const int bandmap3to2[] = {1, 0};
     664             :     static const int bandmap4to2[] = {1, 4};
     665             : 
     666             :     static const int bandmap1to3[] = {1, 1, 1};
     667             :     static const int bandmap2to3[] = {1, 1, 1};
     668             :     static const int bandmap3to3[] = {1, 2, 3};
     669             :     static const int bandmap4to3[] = {1, 2, 3};
     670             : 
     671             :     static const int bandmap1to4[] = {1, 1, 1, 0};
     672             :     static const int bandmap2to4[] = {1, 1, 1, 2};
     673             :     static const int bandmap3to4[] = {1, 2, 3, 0};
     674             :     static const int bandmap4to4[] = {1, 2, 3, 4};
     675             : 
     676             :     static const int *const bandmap_selector[4][4] = {
     677             :         {bandmap1to1, bandmap2to1, bandmap3to1, bandmap4to1},
     678             :         {bandmap1to2, bandmap2to2, bandmap3to2, bandmap4to2},
     679             :         {bandmap1to3, bandmap2to3, bandmap3to3, bandmap4to3},
     680             :         {bandmap1to4, bandmap2to4, bandmap3to4, bandmap4to4},
     681             :     };
     682             : 
     683          53 :     if (nSourceBands > 4 || nSourceBands < 1)
     684             :     {
     685           0 :         return nullptr;
     686             :     }
     687          53 :     if (nWmsBands > 4 || nWmsBands < 1)
     688             :     {
     689           0 :         return nullptr;
     690             :     }
     691          53 :     return bandmap_selector[nWmsBands - 1][nSourceBands - 1];
     692             : }
     693             : 
     694          53 : CPLErr GDALWMSRasterBand::ReadBlockFromDataset(GDALDataset *ds, int x, int y,
     695             :                                                int to_buffer_band, void *buffer,
     696             :                                                int advise_read)
     697             : {
     698          53 :     CPLErr ret = CE_None;
     699          53 :     GByte *color_table = nullptr;
     700             :     int i;
     701             : 
     702             :     // CPLDebug("WMS", "ReadBlockFromDataset: to_buffer_band=%d, (x,y)=(%d,
     703             :     // %d)", to_buffer_band, x, y);
     704             : 
     705             :     /* expected size */
     706          53 :     const int esx = MIN(MAX(0, (x + 1) * nBlockXSize), nRasterXSize) -
     707          53 :                     MIN(MAX(0, x * nBlockXSize), nRasterXSize);
     708          53 :     const int esy = MIN(MAX(0, (y + 1) * nBlockYSize), nRasterYSize) -
     709          53 :                     MIN(MAX(0, y * nBlockYSize), nRasterYSize);
     710             : 
     711          53 :     int sx = ds->GetRasterXSize();
     712          53 :     int sy = ds->GetRasterYSize();
     713             :     /* Allow bigger than expected so pre-tiled constant size images work on
     714             :      * corners */
     715          53 :     if ((sx > nBlockXSize) || (sy > nBlockYSize) || (sx < esx) || (sy < esy))
     716             :     {
     717           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     718             :                  "GDALWMS: Incorrect size %d x %d of downloaded block, "
     719             :                  "expected %d x %d, max %d x %d.",
     720             :                  sx, sy, esx, esy, nBlockXSize, nBlockYSize);
     721           0 :         ret = CE_Failure;
     722             :     }
     723             : 
     724          53 :     int nDSRasterCount = ds->GetRasterCount();
     725          53 :     if (ret == CE_None)
     726             :     {
     727          53 :         if (nDSRasterCount != m_parent_dataset->nBands)
     728             :         {
     729             :             /* Maybe its an image with color table */
     730          34 :             if ((eDataType == GDT_Byte) && (ds->GetRasterCount() == 1))
     731             :             {
     732          24 :                 GDALRasterBand *rb = ds->GetRasterBand(1);
     733          24 :                 if (rb->GetRasterDataType() == GDT_Byte)
     734             :                 {
     735          24 :                     GDALColorTable *ct = rb->GetColorTable();
     736          24 :                     if (ct != nullptr)
     737             :                     {
     738          19 :                         if (!advise_read)
     739             :                         {
     740          19 :                             color_table = new GByte[256 * 4];
     741             :                             const int count =
     742          19 :                                 MIN(256, ct->GetColorEntryCount());
     743         796 :                             for (i = 0; i < count; ++i)
     744             :                             {
     745             :                                 GDALColorEntry ce;
     746         777 :                                 ct->GetColorEntryAsRGB(i, &ce);
     747         777 :                                 color_table[i] = static_cast<GByte>(ce.c1);
     748         777 :                                 color_table[i + 256] =
     749         777 :                                     static_cast<GByte>(ce.c2);
     750         777 :                                 color_table[i + 512] =
     751         777 :                                     static_cast<GByte>(ce.c3);
     752         777 :                                 color_table[i + 768] =
     753         777 :                                     static_cast<GByte>(ce.c4);
     754             :                             }
     755             : 
     756        4106 :                             for (i = count; i < 256; ++i)
     757             :                             {
     758        4087 :                                 color_table[i] = 0;
     759        4087 :                                 color_table[i + 256] = 0;
     760        4087 :                                 color_table[i + 512] = 0;
     761        4087 :                                 color_table[i + 768] = 0;
     762             :                             }
     763             :                         }
     764             :                     }
     765           5 :                     else if (m_parent_dataset->nBands <= 4)
     766             :                     {  // Promote single band to fake color table
     767           5 :                         color_table = new GByte[256 * 4];
     768        1285 :                         for (i = 0; i < 256; i++)
     769             :                         {
     770        1280 :                             color_table[i] = static_cast<GByte>(i);
     771        1280 :                             color_table[i + 256] = static_cast<GByte>(i);
     772        1280 :                             color_table[i + 512] = static_cast<GByte>(i);
     773        1280 :                             color_table[i + 768] = 255;  // Transparency
     774             :                         }
     775           5 :                         if (m_parent_dataset->nBands == 2)
     776             :                         {  // Luma-Alpha fixup
     777           0 :                             for (i = 0; i < 256; i++)
     778             :                             {
     779           0 :                                 color_table[i + 256] = 255;
     780             :                             }
     781             :                         }
     782             :                     }
     783             :                 }
     784             :             }
     785             :         }
     786             :     }
     787             : 
     788          53 :     if (!advise_read)
     789             :     {
     790             :         const int *const bandmap =
     791          53 :             GetBandMapForExpand(nDSRasterCount, m_parent_dataset->nBands);
     792         219 :         for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
     793             :         {
     794         166 :             if (ret == CE_None)
     795             :             {
     796         166 :                 void *p = nullptr;
     797         166 :                 GDALRasterBlock *b = nullptr;
     798         166 :                 if ((buffer != nullptr) && (ib == to_buffer_band))
     799             :                 {
     800          33 :                     p = buffer;
     801             :                 }
     802             :                 else
     803             :                 {
     804             :                     GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(
     805         133 :                         m_parent_dataset->GetRasterBand(ib));
     806         133 :                     if (m_overview >= 0)
     807             :                     {
     808             :                         band = static_cast<GDALWMSRasterBand *>(
     809          73 :                             band->GetOverview(m_overview));
     810             :                     }
     811         133 :                     if (!band->IsBlockInCache(x, y))
     812             :                     {
     813         133 :                         b = band->GetLockedBlockRef(x, y, true);
     814         133 :                         if (b != nullptr)
     815             :                         {
     816         133 :                             p = b->GetDataRef();
     817         133 :                             if (p == nullptr)
     818             :                             {
     819           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
     820             :                                          "GDALWMS: GetDataRef returned NULL.");
     821           0 :                                 ret = CE_Failure;
     822             :                             }
     823             :                         }
     824             :                     }
     825             :                     else
     826             :                     {
     827             :                         // CPLDebug("WMS", "Band %d, block (x,y)=(%d, %d)
     828             :                         // already in cache", band->GetBand(), x, y);
     829             :                     }
     830             :                 }
     831             : 
     832         166 :                 if (p != nullptr)
     833             :                 {
     834         166 :                     int pixel_space = GDALGetDataTypeSizeBytes(eDataType);
     835         166 :                     int line_space = pixel_space * nBlockXSize;
     836         166 :                     if (color_table == nullptr)
     837             :                     {
     838          88 :                         if (bandmap == nullptr || bandmap[ib - 1] != 0)
     839             :                         {
     840          87 :                             GDALDataType dt = eDataType;
     841          87 :                             int nSourceBand = ib;
     842          87 :                             if (bandmap != nullptr)
     843             :                             {
     844          87 :                                 nSourceBand = bandmap[ib - 1];
     845             :                             }
     846             :                             // Get the data from the PNG as stored instead of
     847             :                             // converting, if the server asks for that
     848             :                             // TODO: This hack is from #3493 - not sure it
     849             :                             // really belongs here.
     850          87 :                             if ((GDT_Int16 == dt) &&
     851             :                                 (GDT_UInt16 ==
     852           0 :                                  ds->GetRasterBand(ib)->GetRasterDataType()))
     853             :                             {
     854           0 :                                 dt = GDT_UInt16;
     855             :                             }
     856             : 
     857          87 :                             if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy,
     858             :                                              dt, 1, &nSourceBand, pixel_space,
     859          87 :                                              line_space, 0, nullptr) != CE_None)
     860             :                             {
     861           0 :                                 CPLError(CE_Failure, CPLE_AppDefined,
     862             :                                          "GDALWMS: RasterIO failed on "
     863             :                                          "downloaded block.");
     864           0 :                                 ret = CE_Failure;
     865          87 :                             }
     866             :                         }
     867             :                         else  // if( bandmap != nullptr && bandmap[ib - 1] == 0
     868             :                               // )
     869             :                         {  // parent expects 4 bands but file has fewer count so
     870             :                             // generate a all "opaque" 4th band
     871           1 :                             GByte *byte_buffer = reinterpret_cast<GByte *>(p);
     872         129 :                             for (int l_y = 0; l_y < sy; ++l_y)
     873             :                             {
     874       16512 :                                 for (int l_x = 0; l_x < sx; ++l_x)
     875             :                                 {
     876       16384 :                                     const int offset = l_x + l_y * line_space;
     877       16384 :                                     byte_buffer[offset] =
     878             :                                         255;  // fill with opaque
     879             :                                 }
     880             :                             }
     881             :                         }
     882             :                     }
     883          78 :                     else if (ib <= 4)
     884             :                     {
     885          78 :                         if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy,
     886             :                                          eDataType, 1, nullptr, pixel_space,
     887          78 :                                          line_space, 0, nullptr) != CE_None)
     888             :                         {
     889           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     890             :                                      "GDALWMS: RasterIO failed on downloaded "
     891             :                                      "block.");
     892           0 :                             ret = CE_Failure;
     893             :                         }
     894             : 
     895          78 :                         if (ret == CE_None)
     896             :                         {
     897          78 :                             GByte *band_color_table =
     898          78 :                                 color_table + 256 * (ib - 1);
     899          78 :                             GByte *byte_buffer = reinterpret_cast<GByte *>(p);
     900       20558 :                             for (int l_y = 0; l_y < sy; ++l_y)
     901             :                             {
     902     5918720 :                                 for (int l_x = 0; l_x < sx; ++l_x)
     903             :                                 {
     904     5898240 :                                     const int offset = l_x + l_y * line_space;
     905     5898240 :                                     byte_buffer[offset] =
     906     5898240 :                                         band_color_table[byte_buffer[offset]];
     907             :                                 }
     908             :                             }
     909             :                         }
     910             :                     }
     911             :                     else
     912             :                     {
     913           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     914             :                                  "GDALWMS: Color table supports at most 4 "
     915             :                                  "components.");
     916           0 :                         ret = CE_Failure;
     917             :                     }
     918             :                 }
     919         166 :                 if (b != nullptr)
     920             :                 {
     921         133 :                     b->DropLock();
     922             :                 }
     923             :             }
     924             :         }
     925             :     }
     926          53 :     GDALClose(ds);
     927             : 
     928          53 :     if (color_table != nullptr)
     929             :     {
     930          24 :         delete[] color_table;
     931             :     }
     932             : 
     933          53 :     return ret;
     934             : }
     935             : 
     936          41 : CPLErr GDALWMSRasterBand::ReadBlockFromFile(const CPLString &soFileName, int x,
     937             :                                             int y, int to_buffer_band,
     938             :                                             void *buffer, int advise_read)
     939             : {
     940          41 :     GDALDataset *ds = GDALDataset::FromHandle(GDALOpenEx(
     941             :         soFileName, GDAL_OF_RASTER | GDAL_OF_READONLY | GDAL_OF_VERBOSE_ERROR,
     942          41 :         nullptr, m_parent_dataset->m_tileOO, nullptr));
     943          41 :     if (ds == nullptr)
     944             :     {
     945           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     946             :                  "GDALWMS: Unable to open downloaded block.");
     947           0 :         return CE_Failure;
     948             :     }
     949             : 
     950          41 :     return ReadBlockFromDataset(ds, x, y, to_buffer_band, buffer, advise_read);
     951             : }
     952             : 
     953          14 : CPLErr GDALWMSRasterBand::ReadBlockFromCache(const char *pszKey, int x, int y,
     954             :                                              int to_buffer_band, void *buffer,
     955             :                                              int advise_read)
     956             : {
     957          14 :     GDALWMSCache *cache = m_parent_dataset->m_cache;
     958          14 :     if (nullptr == cache)
     959             :     {
     960           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     961             :                  "GDALWMS: Unable to open downloaded block.");
     962           0 :         return CE_Failure;
     963             :     }
     964          14 :     GDALDataset *ds = cache->GetDataset(pszKey, m_parent_dataset->m_tileOO);
     965          14 :     if (ds == nullptr)
     966             :     {
     967           2 :         CPLError(CE_Failure, CPLE_AppDefined,
     968             :                  "GDALWMS: Unable to open downloaded block.");
     969           2 :         return CE_Failure;
     970             :     }
     971             : 
     972          12 :     return ReadBlockFromDataset(ds, x, y, to_buffer_band, buffer, advise_read);
     973             : }
     974             : 
     975           2 : CPLErr GDALWMSRasterBand::EmptyBlock(int x, int y, int to_buffer_band,
     976             :                                      void *buffer)
     977             : {
     978           2 :     CPLErr ret = CE_None;
     979             : 
     980          10 :     for (int ib = 1; ib <= m_parent_dataset->nBands; ++ib)
     981             :     {
     982           8 :         if (ret == CE_None)
     983             :         {
     984           8 :             void *p = nullptr;
     985           8 :             GDALRasterBlock *b = nullptr;
     986             :             GDALWMSRasterBand *band = static_cast<GDALWMSRasterBand *>(
     987           8 :                 m_parent_dataset->GetRasterBand(ib));
     988           8 :             if (m_overview >= 0)
     989             :                 band = static_cast<GDALWMSRasterBand *>(
     990           0 :                     band->GetOverview(m_overview));
     991           8 :             if ((buffer != nullptr) && (ib == to_buffer_band))
     992             :             {
     993           2 :                 p = buffer;
     994             :             }
     995             :             else
     996             :             {
     997           6 :                 if (!band->IsBlockInCache(x, y))
     998             :                 {
     999           6 :                     b = band->GetLockedBlockRef(x, y, true);
    1000           6 :                     if (b != nullptr)
    1001             :                     {
    1002           6 :                         p = b->GetDataRef();
    1003           6 :                         if (p == nullptr)
    1004             :                         {
    1005           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1006             :                                      "GDALWMS: GetDataRef returned NULL.");
    1007           0 :                             ret = CE_Failure;
    1008             :                         }
    1009             :                     }
    1010             :                 }
    1011             :             }
    1012           8 :             if (p != nullptr)
    1013             :             {
    1014             :                 int hasNDV;
    1015           8 :                 double valNDV = band->GetNoDataValue(&hasNDV);
    1016           8 :                 if (!hasNDV)
    1017           8 :                     valNDV = 0;
    1018           8 :                 GDALCopyWords(&valNDV, GDT_Float64, 0, p, eDataType,
    1019             :                               GDALGetDataTypeSizeBytes(eDataType),
    1020           8 :                               nBlockXSize * nBlockYSize);
    1021             :             }
    1022           8 :             if (b != nullptr)
    1023             :             {
    1024           6 :                 b->DropLock();
    1025             :             }
    1026             :         }
    1027             :     }
    1028             : 
    1029           2 :     return ret;
    1030             : }
    1031             : 
    1032           0 : CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name)
    1033             : {
    1034           0 :     CPLErr ret = CE_None;
    1035           0 :     int reported_errors_count = 0;
    1036             : 
    1037           0 :     CPLXMLNode *orig_root = CPLParseXMLFile(file_name);
    1038           0 :     CPLXMLNode *root = orig_root;
    1039           0 :     if (root != nullptr)
    1040             :     {
    1041           0 :         root = CPLGetXMLNode(root, "=ServiceExceptionReport");
    1042             :     }
    1043           0 :     if (root != nullptr)
    1044             :     {
    1045           0 :         CPLXMLNode *n = CPLGetXMLNode(root, "ServiceException");
    1046           0 :         while (n != nullptr)
    1047             :         {
    1048           0 :             const char *exception = CPLGetXMLValue(n, "=ServiceException", "");
    1049             :             const char *exception_code =
    1050           0 :                 CPLGetXMLValue(n, "=ServiceException.code", "");
    1051           0 :             if (exception[0] != '\0')
    1052             :             {
    1053           0 :                 if (exception_code[0] != '\0')
    1054             :                 {
    1055           0 :                     CPLError(
    1056             :                         CE_Failure, CPLE_AppDefined,
    1057             :                         "GDALWMS: The server returned exception code '%s': %s",
    1058             :                         exception_code, exception);
    1059           0 :                     ++reported_errors_count;
    1060             :                 }
    1061             :                 else
    1062             :                 {
    1063           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1064             :                              "GDALWMS: The server returned exception: %s",
    1065             :                              exception);
    1066           0 :                     ++reported_errors_count;
    1067             :                 }
    1068             :             }
    1069           0 :             else if (exception_code[0] != '\0')
    1070             :             {
    1071           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1072             :                          "GDALWMS: The server returned exception code '%s'.",
    1073             :                          exception_code);
    1074           0 :                 ++reported_errors_count;
    1075             :             }
    1076             : 
    1077           0 :             n = n->psNext;
    1078           0 :             if (n != nullptr)
    1079             :             {
    1080           0 :                 n = CPLGetXMLNode(n, "=ServiceException");
    1081             :             }
    1082             :         }
    1083             :     }
    1084             :     else
    1085             :     {
    1086           0 :         ret = CE_Failure;
    1087             :     }
    1088           0 :     if (orig_root != nullptr)
    1089             :     {
    1090           0 :         CPLDestroyXMLNode(orig_root);
    1091             :     }
    1092             : 
    1093           0 :     if (reported_errors_count == 0)
    1094             :     {
    1095           0 :         ret = CE_Failure;
    1096             :     }
    1097             : 
    1098           0 :     return ret;
    1099             : }
    1100             : 
    1101           0 : CPLErr GDALWMSRasterBand::AdviseRead(int nXOff, int nYOff, int nXSize,
    1102             :                                      int nYSize, int nBufXSize, int nBufYSize,
    1103             :                                      GDALDataType eDT, char **papszOptions)
    1104             : {
    1105             :     //    printf("AdviseRead(%d, %d, %d, %d)\n", nXOff, nYOff, nXSize, nYSize);
    1106           0 :     if (m_parent_dataset->m_offline_mode ||
    1107           0 :         !m_parent_dataset->m_use_advise_read)
    1108           0 :         return CE_None;
    1109           0 :     if (m_parent_dataset->m_cache == nullptr)
    1110           0 :         return CE_Failure;
    1111             : 
    1112             :     /* ==================================================================== */
    1113             :     /*      Do we have overviews that would be appropriate to satisfy       */
    1114             :     /*      this request?                                                   */
    1115             :     /* ==================================================================== */
    1116           0 :     if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
    1117             :     {
    1118           0 :         const int nOverview = GDALBandGetBestOverviewLevel2(
    1119             :             this, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, nullptr);
    1120           0 :         if (nOverview >= 0)
    1121             :         {
    1122           0 :             GDALRasterBand *poOverviewBand = GetOverview(nOverview);
    1123           0 :             if (poOverviewBand == nullptr)
    1124           0 :                 return CE_Failure;
    1125             : 
    1126           0 :             return poOverviewBand->AdviseRead(nXOff, nYOff, nXSize, nYSize,
    1127             :                                               nBufXSize, nBufYSize, eDT,
    1128           0 :                                               papszOptions);
    1129             :         }
    1130             :     }
    1131             : 
    1132           0 :     int bx0 = nXOff / nBlockXSize;
    1133           0 :     int by0 = nYOff / nBlockYSize;
    1134           0 :     int bx1 = (nXOff + nXSize - 1) / nBlockXSize;
    1135           0 :     int by1 = (nYOff + nYSize - 1) / nBlockYSize;
    1136             : 
    1137             :     // Avoid downloading a insane number of tiles
    1138           0 :     const int MAX_TILES = 1000;  // arbitrary number
    1139           0 :     if ((bx1 - bx0 + 1) > MAX_TILES / (by1 - by0 + 1))
    1140             :     {
    1141           0 :         CPLDebug("WMS", "Too many tiles for AdviseRead()");
    1142           0 :         return CE_Failure;
    1143             :     }
    1144             : 
    1145           0 :     if (m_nAdviseReadBX0 == bx0 && m_nAdviseReadBY0 == by0 &&
    1146           0 :         m_nAdviseReadBX1 == bx1 && m_nAdviseReadBY1 == by1)
    1147             :     {
    1148           0 :         return CE_None;
    1149             :     }
    1150           0 :     m_nAdviseReadBX0 = bx0;
    1151           0 :     m_nAdviseReadBY0 = by0;
    1152           0 :     m_nAdviseReadBX1 = bx1;
    1153           0 :     m_nAdviseReadBY1 = by1;
    1154             : 
    1155           0 :     return ReadBlocks(0, 0, nullptr, bx0, by0, bx1, by1, 1);
    1156             : }
    1157             : 
    1158         415 : GDALColorInterp GDALWMSRasterBand::GetColorInterpretation()
    1159             : {
    1160         415 :     return m_color_interp;
    1161             : }
    1162             : 
    1163           9 : CPLErr GDALWMSRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
    1164             : {
    1165           9 :     m_color_interp = eNewInterp;
    1166           9 :     return CE_None;
    1167             : }
    1168             : 
    1169             : // Utility function, returns a value from a vector corresponding to the band
    1170             : // index or the first entry
    1171           0 : static double getBandValue(const std::vector<double> &v, size_t idx)
    1172             : {
    1173           0 :     idx--;
    1174           0 :     if (v.size() > idx)
    1175           0 :         return v[idx];
    1176           0 :     return v[0];
    1177             : }
    1178             : 
    1179         493 : double GDALWMSRasterBand::GetNoDataValue(int *pbSuccess)
    1180             : {
    1181         493 :     std::vector<double> &v = m_parent_dataset->vNoData;
    1182         493 :     if (v.empty())
    1183         493 :         return GDALPamRasterBand::GetNoDataValue(pbSuccess);
    1184           0 :     if (pbSuccess)
    1185           0 :         *pbSuccess = TRUE;
    1186           0 :     return getBandValue(v, nBand);
    1187             : }
    1188             : 
    1189           0 : double GDALWMSRasterBand::GetMinimum(int *pbSuccess)
    1190             : {
    1191           0 :     std::vector<double> &v = m_parent_dataset->vMin;
    1192           0 :     if (v.empty())
    1193           0 :         return GDALPamRasterBand::GetMinimum(pbSuccess);
    1194           0 :     if (pbSuccess)
    1195           0 :         *pbSuccess = TRUE;
    1196           0 :     return getBandValue(v, nBand);
    1197             : }
    1198             : 
    1199           0 : double GDALWMSRasterBand::GetMaximum(int *pbSuccess)
    1200             : {
    1201           0 :     std::vector<double> &v = m_parent_dataset->vMax;
    1202           0 :     if (v.empty())
    1203           0 :         return GDALPamRasterBand::GetMaximum(pbSuccess);
    1204           0 :     if (pbSuccess)
    1205           0 :         *pbSuccess = TRUE;
    1206           0 :     return getBandValue(v, nBand);
    1207             : }
    1208             : 
    1209         316 : GDALColorTable *GDALWMSRasterBand::GetColorTable()
    1210             : {
    1211         316 :     return m_parent_dataset->m_poColorTable;
    1212             : }

Generated by: LCOV version 1.14