LCOV - code coverage report
Current view: top level - frmts/wms - gdalwmsdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 297 398 74.6 %
Date: 2024-11-21 22:18:42 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  WMS Client Driver
       4             :  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
       5             :  *           and other similar services.
       6             :  * Author:   Adam Nowacki, nowak@xpam.de
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2007, Adam Nowacki
      10             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      11             :  * Copyright (c) 2017, Dmitry Baryshnikov, <polimax@mail.ru>
      12             :  * Copyright (c) 2017, NextGIS, <info@nextgis.com>
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  ****************************************************************************
      16             :  *
      17             :  * dataset.cpp:
      18             :  * Initialization of the GDALWMSdriver, parsing the XML configuration file,
      19             :  * instantiation of the minidrivers and accessors used by minidrivers.
      20             :  *
      21             :  ***************************************************************************/
      22             : 
      23             : #include "wmsdriver.h"
      24             : #include "minidriver_wms.h"
      25             : #include "minidriver_tileservice.h"
      26             : #include "minidriver_worldwind.h"
      27             : #include "minidriver_tms.h"
      28             : #include "minidriver_tiled_wms.h"
      29             : #include "minidriver_virtualearth.h"
      30             : 
      31             : #include <algorithm>
      32             : 
      33             : /************************************************************************/
      34             : /*                           GDALWMSDataset()                           */
      35             : /************************************************************************/
      36         349 : GDALWMSDataset::GDALWMSDataset()
      37             :     : m_mini_driver(nullptr), m_cache(nullptr), m_poColorTable(nullptr),
      38             :       m_data_type(GDT_Byte), m_block_size_x(0), m_block_size_y(0),
      39             :       m_use_advise_read(0), m_verify_advise_read(0), m_offline_mode(0),
      40             :       m_http_max_conn(0), m_http_timeout(0), m_http_options(nullptr),
      41             :       m_tileOO(nullptr), m_clamp_requests(true), m_unsafeSsl(false),
      42             :       m_zeroblock_on_serverexceptions(0), m_default_block_size_x(1024),
      43             :       m_default_block_size_y(1024), m_default_tile_count_x(1),
      44             :       m_default_tile_count_y(1), m_default_overview_count(-1),
      45         349 :       m_bNeedsDataWindow(true)
      46             : {
      47         349 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      48         349 :     m_hint.m_valid = false;
      49         349 :     m_data_window.m_sx = -1;
      50         349 :     nBands = 0;
      51         349 : }
      52             : 
      53             : /************************************************************************/
      54             : /*                          ~GDALWMSDataset()                           */
      55             : /************************************************************************/
      56         698 : GDALWMSDataset::~GDALWMSDataset()
      57             : {
      58         349 :     if (m_mini_driver)
      59         347 :         delete m_mini_driver;
      60         349 :     if (m_cache)
      61         213 :         delete m_cache;
      62         349 :     if (m_poColorTable)
      63           0 :         delete m_poColorTable;
      64         349 :     CSLDestroy(m_http_options);
      65         349 :     CSLDestroy(m_tileOO);
      66         698 : }
      67             : 
      68             : /************************************************************************/
      69             : /*                             Initialize()                             */
      70             : /************************************************************************/
      71         349 : CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config, char **l_papszOpenOptions)
      72             : {
      73         349 :     CPLErr ret = CE_None;
      74             : 
      75         349 :     char *pszXML = CPLSerializeXMLTree(config);
      76         349 :     if (pszXML)
      77             :     {
      78         349 :         m_osXML = pszXML;
      79         349 :         CPLFree(pszXML);
      80             :     }
      81             : 
      82             :     // Generic options that apply to all minidrivers
      83             : 
      84             :     // UserPwd
      85         349 :     const char *pszUserPwd = CPLGetXMLValue(config, "UserPwd", "");
      86         349 :     if (pszUserPwd[0] != '\0')
      87           0 :         m_osUserPwd = pszUserPwd;
      88             : 
      89         349 :     const char *pszUserAgent = CPLGetXMLValue(config, "UserAgent", "");
      90         349 :     if (pszUserAgent[0] != '\0')
      91           0 :         m_osUserAgent = pszUserAgent;
      92             :     else
      93         349 :         m_osUserAgent = CPLGetConfigOption("GDAL_HTTP_USERAGENT", "");
      94             : 
      95         349 :     const char *pszReferer = CPLGetXMLValue(config, "Referer", "");
      96         349 :     if (pszReferer[0] != '\0')
      97           0 :         m_osReferer = pszReferer;
      98             : 
      99             :     {
     100             :         const char *pszHttpZeroBlockCodes =
     101         349 :             CPLGetXMLValue(config, "ZeroBlockHttpCodes", "");
     102         349 :         if (pszHttpZeroBlockCodes[0] == '\0')
     103             :         {
     104         261 :             m_http_zeroblock_codes.insert(204);
     105             :         }
     106             :         else
     107             :         {
     108          88 :             char **kv = CSLTokenizeString2(pszHttpZeroBlockCodes, ",",
     109             :                                            CSLT_HONOURSTRINGS);
     110         264 :             for (int i = 0; i < CSLCount(kv); i++)
     111             :             {
     112         176 :                 int code = atoi(kv[i]);
     113         176 :                 if (code <= 0)
     114             :                 {
     115           0 :                     CPLError(
     116             :                         CE_Failure, CPLE_AppDefined,
     117             :                         "GDALWMS: Invalid value of ZeroBlockHttpCodes "
     118             :                         "\"%s\", comma separated HTTP response codes expected.",
     119           0 :                         kv[i]);
     120           0 :                     ret = CE_Failure;
     121           0 :                     break;
     122             :                 }
     123         176 :                 m_http_zeroblock_codes.insert(code);
     124             :             }
     125          88 :             CSLDestroy(kv);
     126             :         }
     127             :     }
     128             : 
     129         349 :     if (ret == CE_None)
     130             :     {
     131             :         const char *pszZeroExceptions =
     132         349 :             CPLGetXMLValue(config, "ZeroBlockOnServerException", "");
     133         349 :         if (pszZeroExceptions[0] != '\0')
     134             :         {
     135          88 :             m_zeroblock_on_serverexceptions = StrToBool(pszZeroExceptions);
     136          88 :             if (m_zeroblock_on_serverexceptions == -1)
     137             :             {
     138           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     139             :                          "GDALWMS: Invalid value of ZeroBlockOnServerException "
     140             :                          "\"%s\", true/false expected.",
     141             :                          pszZeroExceptions);
     142           0 :                 ret = CE_Failure;
     143             :             }
     144             :         }
     145             :     }
     146             : 
     147         349 :     if (ret == CE_None)
     148             :     {
     149         349 :         const char *max_conn = CPLGetXMLValue(config, "MaxConnections", "");
     150         349 :         if (max_conn[0] == '\0')
     151             :         {
     152         263 :             max_conn = CPLGetConfigOption("GDAL_MAX_CONNECTIONS", "");
     153             :         }
     154         349 :         if (max_conn[0] != '\0')
     155             :         {
     156          86 :             m_http_max_conn = atoi(max_conn);
     157             :         }
     158             :         else
     159             :         {
     160         263 :             m_http_max_conn = 2;
     161             :         }
     162             :     }
     163             : 
     164         349 :     if (ret == CE_None)
     165             :     {
     166         349 :         const char *timeout = CPLGetXMLValue(config, "Timeout", "");
     167         349 :         if (timeout[0] != '\0')
     168             :         {
     169           0 :             m_http_timeout = atoi(timeout);
     170             :         }
     171             :         else
     172             :         {
     173         349 :             m_http_timeout =
     174         349 :                 atoi(CPLGetConfigOption("GDAL_HTTP_TIMEOUT", "300"));
     175             :         }
     176             :     }
     177             : 
     178         349 :     if (ret == CE_None)
     179             :     {
     180         349 :         m_osAccept = CPLGetXMLValue(config, "Accept", "");
     181             :     }
     182             : 
     183         349 :     if (ret == CE_None)
     184             :     {
     185         349 :         const char *offline_mode = CPLGetXMLValue(config, "OfflineMode", "");
     186         349 :         if (offline_mode[0] != '\0')
     187             :         {
     188           0 :             const int offline_mode_bool = StrToBool(offline_mode);
     189           0 :             if (offline_mode_bool == -1)
     190             :             {
     191           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     192             :                          "GDALWMS: Invalid value of OfflineMode, true / false "
     193             :                          "expected.");
     194           0 :                 ret = CE_Failure;
     195             :             }
     196             :             else
     197             :             {
     198           0 :                 m_offline_mode = offline_mode_bool;
     199             :             }
     200             :         }
     201             :         else
     202             :         {
     203         349 :             m_offline_mode = 0;
     204             :         }
     205             :     }
     206             : 
     207         349 :     if (ret == CE_None)
     208             :     {
     209         349 :         const char *advise_read = CPLGetXMLValue(config, "AdviseRead", "");
     210         349 :         if (advise_read[0] != '\0')
     211             :         {
     212           0 :             const int advise_read_bool = StrToBool(advise_read);
     213           0 :             if (advise_read_bool == -1)
     214             :             {
     215           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     216             :                          "GDALWMS: Invalid value of AdviseRead, true / false "
     217             :                          "expected.");
     218           0 :                 ret = CE_Failure;
     219             :             }
     220             :             else
     221             :             {
     222           0 :                 m_use_advise_read = advise_read_bool;
     223             :             }
     224             :         }
     225             :         else
     226             :         {
     227         349 :             m_use_advise_read = 0;
     228             :         }
     229             :     }
     230             : 
     231         349 :     if (ret == CE_None)
     232             :     {
     233             :         const char *verify_advise_read =
     234         349 :             CPLGetXMLValue(config, "VerifyAdviseRead", "");
     235         349 :         if (m_use_advise_read)
     236             :         {
     237           0 :             if (verify_advise_read[0] != '\0')
     238             :             {
     239             :                 const int verify_advise_read_bool =
     240           0 :                     StrToBool(verify_advise_read);
     241           0 :                 if (verify_advise_read_bool == -1)
     242             :                 {
     243           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     244             :                              "GDALWMS: Invalid value of VerifyAdviseRead, true "
     245             :                              "/ false expected.");
     246           0 :                     ret = CE_Failure;
     247             :                 }
     248             :                 else
     249             :                 {
     250           0 :                     m_verify_advise_read = verify_advise_read_bool;
     251             :                 }
     252             :             }
     253             :             else
     254             :             {
     255           0 :                 m_verify_advise_read = 1;
     256             :             }
     257             :         }
     258             :     }
     259             : 
     260         349 :     CPLXMLNode *service_node = CPLGetXMLNode(config, "Service");
     261         349 :     if (service_node == nullptr)
     262             :     {
     263           0 :         CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: No Service specified.");
     264           0 :         return CE_Failure;
     265             :     }
     266             : 
     267         349 :     if (ret == CE_None)
     268             :     {
     269             :         const char *pszEnableCache =
     270         349 :             CPLGetConfigOption("GDAL_ENABLE_WMS_CACHE", "YES");
     271         349 :         CPLXMLNode *cache_node = CPLGetXMLNode(config, "Cache");
     272         349 :         if (cache_node != nullptr && CPLTestBool(pszEnableCache))
     273             :         {
     274         213 :             m_cache = new GDALWMSCache();
     275         213 :             if (m_cache->Initialize(
     276             :                     CPLGetXMLValue(service_node, "ServerUrl", nullptr),
     277         213 :                     cache_node) != CE_None)
     278             :             {
     279           0 :                 delete m_cache;
     280           0 :                 m_cache = nullptr;
     281           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     282             :                          "GDALWMS: Failed to initialize cache.");
     283           0 :                 ret = CE_Failure;
     284             :             }
     285             :             else
     286             :             {
     287             :                 // NOTE: Save cache path to metadata. For example, this is
     288             :                 // useful for deleting a cache folder when removing dataset or
     289             :                 // to fill the cache for specified area and zoom levels
     290         213 :                 SetMetadataItem("CACHE_PATH", m_cache->CachePath(), nullptr);
     291             :             }
     292             :         }
     293             :     }
     294             : 
     295         349 :     if (ret == CE_None)
     296             :     {
     297         349 :         const int v = StrToBool(CPLGetXMLValue(config, "UnsafeSSL", "false"));
     298         349 :         if (v == -1)
     299             :         {
     300           0 :             CPLError(
     301             :                 CE_Failure, CPLE_AppDefined,
     302             :                 "GDALWMS: Invalid value of UnsafeSSL: true or false expected.");
     303           0 :             ret = CE_Failure;
     304             :         }
     305             :         else
     306             :         {
     307         349 :             m_unsafeSsl = v;
     308             :         }
     309             :     }
     310             : 
     311             :     // Initialize the minidriver, which can set parameters for the dataset using
     312             :     // member functions
     313             : 
     314         698 :     const CPLString service_name = CPLGetXMLValue(service_node, "name", "");
     315         349 :     if (service_name.empty())
     316             :     {
     317           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     318             :                  "GDALWMS: No Service name specified.");
     319           1 :         return CE_Failure;
     320             :     }
     321             : 
     322         348 :     m_mini_driver = NewWMSMiniDriver(service_name);
     323         348 :     if (m_mini_driver == nullptr)
     324             :     {
     325           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     326             :                  "GDALWMS: No mini-driver registered for '%s'.",
     327             :                  service_name.c_str());
     328           0 :         return CE_Failure;
     329             :     }
     330             : 
     331             :     // Set up minidriver
     332         348 :     m_mini_driver->m_parent_dataset = this;
     333         348 :     if (m_mini_driver->Initialize(service_node, l_papszOpenOptions) != CE_None)
     334             :     {
     335           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     336             :                  "GDALWMS: Failed to initialize minidriver.");
     337           1 :         delete m_mini_driver;
     338           1 :         m_mini_driver = nullptr;
     339           1 :         ret = CE_Failure;
     340             :     }
     341             :     else
     342             :     {
     343         347 :         m_mini_driver->GetCapabilities(&m_mini_driver_caps);
     344             :     }
     345             : 
     346             :     /*
     347             :       Parameters that could be set by minidriver already
     348             :       If the size is set, minidriver has done this already
     349             :       A "server" side minidriver needs to set at least:
     350             :       - Blocksize (x and y)
     351             :       - Clamp flag (defaults to true)
     352             :       - DataWindow
     353             :       - Band Count
     354             :       - Data Type
     355             :       It should also initialize and register the bands and overviews.
     356             :     */
     357             : 
     358         348 :     if (m_data_window.m_sx < 1)
     359             :     {
     360         345 :         int nOverviews = 0;
     361             : 
     362         345 :         if (ret == CE_None)
     363             :         {
     364         344 :             m_block_size_x = atoi(CPLGetXMLValue(
     365             :                 config, "BlockSizeX",
     366         688 :                 CPLString().Printf("%d", m_default_block_size_x)));
     367         344 :             m_block_size_y = atoi(CPLGetXMLValue(
     368             :                 config, "BlockSizeY",
     369         688 :                 CPLString().Printf("%d", m_default_block_size_y)));
     370         344 :             if (m_block_size_x <= 0 || m_block_size_y <= 0)
     371             :             {
     372           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     373             :                          "GDALWMS: Invalid value in BlockSizeX or BlockSizeY");
     374           0 :                 ret = CE_Failure;
     375             :             }
     376             :         }
     377             : 
     378         345 :         if (ret == CE_None)
     379             :         {
     380         344 :             m_clamp_requests =
     381         344 :                 StrToBool(CPLGetXMLValue(config, "ClampRequests", "true"));
     382         344 :             if (m_clamp_requests < 0)
     383             :             {
     384           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     385             :                          "GDALWMS: Invalid value of ClampRequests, true/false "
     386             :                          "expected.");
     387           0 :                 ret = CE_Failure;
     388             :             }
     389             :         }
     390             : 
     391         345 :         if (ret == CE_None)
     392             :         {
     393         344 :             CPLXMLNode *data_window_node = CPLGetXMLNode(config, "DataWindow");
     394         344 :             if (data_window_node == nullptr && m_bNeedsDataWindow)
     395             :             {
     396           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     397             :                          "GDALWMS: DataWindow missing.");
     398           0 :                 ret = CE_Failure;
     399             :             }
     400             :             else
     401             :             {
     402         344 :                 CPLString osDefaultX0, osDefaultX1, osDefaultY0, osDefaultY1;
     403         344 :                 CPLString osDefaultTileCountX, osDefaultTileCountY,
     404         344 :                     osDefaultTileLevel;
     405         344 :                 CPLString osDefaultOverviewCount;
     406         344 :                 osDefaultX0.Printf("%.8f", m_default_data_window.m_x0);
     407         344 :                 osDefaultX1.Printf("%.8f", m_default_data_window.m_x1);
     408         344 :                 osDefaultY0.Printf("%.8f", m_default_data_window.m_y0);
     409         344 :                 osDefaultY1.Printf("%.8f", m_default_data_window.m_y1);
     410         344 :                 osDefaultTileCountX.Printf("%d", m_default_tile_count_x);
     411         344 :                 osDefaultTileCountY.Printf("%d", m_default_tile_count_y);
     412         344 :                 if (m_default_data_window.m_tlevel >= 0)
     413             :                     osDefaultTileLevel.Printf("%d",
     414           1 :                                               m_default_data_window.m_tlevel);
     415         344 :                 if (m_default_overview_count >= 0)
     416             :                     osDefaultOverviewCount.Printf("%d",
     417           1 :                                                   m_default_overview_count);
     418         344 :                 const char *overview_count = CPLGetXMLValue(
     419             :                     config, "OverviewCount", osDefaultOverviewCount);
     420             :                 const char *ulx =
     421         344 :                     CPLGetXMLValue(data_window_node, "UpperLeftX", osDefaultX0);
     422             :                 const char *uly =
     423         344 :                     CPLGetXMLValue(data_window_node, "UpperLeftY", osDefaultY0);
     424         344 :                 const char *lrx = CPLGetXMLValue(data_window_node,
     425             :                                                  "LowerRightX", osDefaultX1);
     426         344 :                 const char *lry = CPLGetXMLValue(data_window_node,
     427             :                                                  "LowerRightY", osDefaultY1);
     428         344 :                 const char *sx = CPLGetXMLValue(data_window_node, "SizeX", "");
     429         344 :                 const char *sy = CPLGetXMLValue(data_window_node, "SizeY", "");
     430         344 :                 const char *tx = CPLGetXMLValue(data_window_node, "TileX", "0");
     431         344 :                 const char *ty = CPLGetXMLValue(data_window_node, "TileY", "0");
     432         344 :                 const char *tlevel = CPLGetXMLValue(
     433             :                     data_window_node, "TileLevel", osDefaultTileLevel);
     434         344 :                 const char *str_tile_count_x = CPLGetXMLValue(
     435             :                     data_window_node, "TileCountX", osDefaultTileCountX);
     436         344 :                 const char *str_tile_count_y = CPLGetXMLValue(
     437             :                     data_window_node, "TileCountY", osDefaultTileCountY);
     438             :                 const char *y_origin =
     439         344 :                     CPLGetXMLValue(data_window_node, "YOrigin", "default");
     440             : 
     441         344 :                 if ((ulx[0] != '\0') && (uly[0] != '\0') && (lrx[0] != '\0') &&
     442         344 :                     (lry[0] != '\0'))
     443             :                 {
     444         344 :                     m_data_window.m_x0 = CPLAtof(ulx);
     445         344 :                     m_data_window.m_y0 = CPLAtof(uly);
     446         344 :                     m_data_window.m_x1 = CPLAtof(lrx);
     447         344 :                     m_data_window.m_y1 = CPLAtof(lry);
     448             :                 }
     449             :                 else
     450             :                 {
     451           0 :                     CPLError(
     452             :                         CE_Failure, CPLE_AppDefined,
     453             :                         "GDALWMS: Mandatory elements of DataWindow missing: "
     454             :                         "UpperLeftX, UpperLeftY, LowerRightX, LowerRightY.");
     455           0 :                     ret = CE_Failure;
     456             :                 }
     457             : 
     458         344 :                 m_data_window.m_tlevel = atoi(tlevel);
     459             :                 // Limit to 30 to avoid 1 << m_tlevel overflow
     460         344 :                 if (m_data_window.m_tlevel < 0 || m_data_window.m_tlevel > 30)
     461             :                 {
     462           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     463             :                              "Invalid value for TileLevel");
     464           0 :                     return CE_Failure;
     465             :                 }
     466             : 
     467         344 :                 if (ret == CE_None)
     468             :                 {
     469         344 :                     if ((sx[0] != '\0') && (sy[0] != '\0'))
     470             :                     {
     471         327 :                         m_data_window.m_sx = atoi(sx);
     472         327 :                         m_data_window.m_sy = atoi(sy);
     473             :                     }
     474          17 :                     else if ((tlevel[0] != '\0') &&
     475          17 :                              (str_tile_count_x[0] != '\0') &&
     476          17 :                              (str_tile_count_y[0] != '\0'))
     477             :                     {
     478          17 :                         const int tile_count_x = atoi(str_tile_count_x);
     479          17 :                         if (tile_count_x <= 0)
     480             :                         {
     481           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     482             :                                      "Invalid value for TileCountX");
     483           0 :                             return CE_Failure;
     484             :                         }
     485          17 :                         if (tile_count_x > INT_MAX / m_block_size_x ||
     486          17 :                             tile_count_x * m_block_size_x >
     487          17 :                                 INT_MAX / (1 << m_data_window.m_tlevel))
     488             :                         {
     489           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     490             :                                      "Integer overflow in tile_count_x * "
     491             :                                      "m_block_size_x * (1 << "
     492             :                                      "m_data_window.m_tlevel)");
     493           0 :                             return CE_Failure;
     494             :                         }
     495          17 :                         m_data_window.m_sx = tile_count_x * m_block_size_x *
     496          17 :                                              (1 << m_data_window.m_tlevel);
     497             : 
     498          17 :                         const int tile_count_y = atoi(str_tile_count_y);
     499          17 :                         if (tile_count_y <= 0)
     500             :                         {
     501           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     502             :                                      "Invalid value for TileCountY");
     503           0 :                             return CE_Failure;
     504             :                         }
     505          17 :                         if (tile_count_y > INT_MAX / m_block_size_y ||
     506          17 :                             tile_count_y * m_block_size_y >
     507          17 :                                 INT_MAX / (1 << m_data_window.m_tlevel))
     508             :                         {
     509           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     510             :                                      "Integer overflow in tile_count_y * "
     511             :                                      "m_block_size_y * (1 << "
     512             :                                      "m_data_window.m_tlevel)");
     513           0 :                             return CE_Failure;
     514             :                         }
     515          17 :                         m_data_window.m_sy = tile_count_y * m_block_size_y *
     516          17 :                                              (1 << m_data_window.m_tlevel);
     517             :                     }
     518             :                     else
     519             :                     {
     520           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     521             :                                  "GDALWMS: Mandatory elements of DataWindow "
     522             :                                  "missing: SizeX, SizeY.");
     523           0 :                         ret = CE_Failure;
     524             :                     }
     525             :                 }
     526         344 :                 if (ret == CE_None)
     527             :                 {
     528         344 :                     if ((tx[0] != '\0') && (ty[0] != '\0'))
     529             :                     {
     530         344 :                         m_data_window.m_tx = atoi(tx);
     531         344 :                         m_data_window.m_ty = atoi(ty);
     532             :                     }
     533             :                     else
     534             :                     {
     535           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     536             :                                  "GDALWMS: Mandatory elements of DataWindow "
     537             :                                  "missing: TileX, TileY.");
     538           0 :                         ret = CE_Failure;
     539             :                     }
     540             :                 }
     541             : 
     542         344 :                 if (ret == CE_None)
     543             :                 {
     544         344 :                     if (overview_count[0] != '\0')
     545             :                     {
     546           5 :                         nOverviews = atoi(overview_count);
     547             :                     }
     548         339 :                     else if (tlevel[0] != '\0')
     549             :                     {
     550         331 :                         nOverviews = m_data_window.m_tlevel;
     551             :                     }
     552             :                     else
     553             :                     {
     554             :                         const int min_overview_size = std::max(
     555           8 :                             32, std::min(m_block_size_x, m_block_size_y));
     556             :                         double a =
     557           8 :                             log(static_cast<double>(std::min(
     558           8 :                                 m_data_window.m_sx, m_data_window.m_sy))) /
     559             :                                 log(2.0) -
     560           8 :                             log(static_cast<double>(min_overview_size)) /
     561           8 :                                 log(2.0);
     562           8 :                         nOverviews = std::max(
     563           8 :                             0, std::min(static_cast<int>(ceil(a)), 32));
     564             :                     }
     565             :                 }
     566         344 :                 if (ret == CE_None)
     567             :                 {
     568         688 :                     CPLString y_origin_str = y_origin;
     569         344 :                     if (y_origin_str == "top")
     570             :                     {
     571         330 :                         m_data_window.m_y_origin = GDALWMSDataWindow::TOP;
     572             :                     }
     573          14 :                     else if (y_origin_str == "bottom")
     574             :                     {
     575           0 :                         m_data_window.m_y_origin = GDALWMSDataWindow::BOTTOM;
     576             :                     }
     577          14 :                     else if (y_origin_str == "default")
     578             :                     {
     579          14 :                         m_data_window.m_y_origin = GDALWMSDataWindow::DEFAULT;
     580             :                     }
     581             :                     else
     582             :                     {
     583           0 :                         CPLError(
     584             :                             CE_Failure, CPLE_AppDefined,
     585             :                             "GDALWMS: DataWindow YOrigin must be set to "
     586             :                             "one of 'default', 'top', or 'bottom', not '%s'.",
     587             :                             y_origin_str.c_str());
     588           0 :                         ret = CE_Failure;
     589             :                     }
     590             :                 }
     591             :             }
     592             :         }
     593             : 
     594         345 :         if (ret == CE_None)
     595             :         {
     596         344 :             if (nBands < 1)
     597         344 :                 nBands = atoi(CPLGetXMLValue(config, "BandsCount", "3"));
     598         344 :             if (nBands < 1)
     599             :             {
     600           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     601             :                          "GDALWMS: Bad number of bands.");
     602           0 :                 ret = CE_Failure;
     603             :             }
     604             :         }
     605             : 
     606         345 :         if (ret == CE_None)
     607             :         {
     608         344 :             const char *data_type = CPLGetXMLValue(config, "DataType", "Byte");
     609         344 :             if (!STARTS_WITH(data_type, "Byte"))
     610           3 :                 SetTileOO("@DATATYPE", data_type);
     611         344 :             m_data_type = GDALGetDataTypeByName(data_type);
     612         344 :             if (m_data_type == GDT_Unknown || m_data_type >= GDT_TypeCount)
     613             :             {
     614           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     615             :                          "GDALWMS: Invalid value in DataType. Data type \"%s\" "
     616             :                          "is not supported.",
     617             :                          data_type);
     618           0 :                 ret = CE_Failure;
     619             :             }
     620             :         }
     621             : 
     622             :         // Initialize the bands and the overviews.  Assumes overviews are powers
     623             :         // of two
     624         345 :         if (ret == CE_None)
     625             :         {
     626         344 :             nRasterXSize = m_data_window.m_sx;
     627         344 :             nRasterYSize = m_data_window.m_sy;
     628             : 
     629         688 :             if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) ||
     630         344 :                 !GDALCheckBandCount(nBands, TRUE))
     631             :             {
     632           0 :                 return CE_Failure;
     633             :             }
     634             : 
     635         344 :             GDALColorInterp default_color_interp[4][4] = {
     636             :                 {GCI_GrayIndex, GCI_Undefined, GCI_Undefined, GCI_Undefined},
     637             :                 {GCI_GrayIndex, GCI_AlphaBand, GCI_Undefined, GCI_Undefined},
     638             :                 {GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_Undefined},
     639             :                 {GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand}};
     640        1663 :             for (int i = 0; i < nBands; ++i)
     641             :             {
     642        1319 :                 GDALColorInterp color_interp =
     643        1319 :                     (nBands <= 4 && i <= 3 ? default_color_interp[nBands - 1][i]
     644             :                                            : GCI_Undefined);
     645        1319 :                 GDALWMSRasterBand *band = new GDALWMSRasterBand(this, i, 1.0);
     646        1319 :                 band->m_color_interp = color_interp;
     647        1319 :                 SetBand(i + 1, band);
     648        1319 :                 double scale = 0.5;
     649        6858 :                 for (int j = 0; j < nOverviews; ++j)
     650             :                 {
     651        5539 :                     if (!band->AddOverview(scale))
     652           0 :                         break;
     653        5539 :                     band->m_color_interp = color_interp;
     654        5539 :                     scale *= 0.5;
     655             :                 }
     656             :             }
     657             :         }
     658             :     }
     659             : 
     660             :     // Let the local configuration override the minidriver supplied projection
     661         348 :     if (ret == CE_None)
     662             :     {
     663         347 :         const char *proj = CPLGetXMLValue(config, "Projection", "");
     664         347 :         if (proj[0] != '\0')
     665             :         {
     666         160 :             m_oSRS = ProjToSRS(proj);
     667         160 :             if (m_oSRS.IsEmpty())
     668             :             {
     669           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     670             :                          "GDALWMS: Bad projection specified.");
     671           0 :                 ret = CE_Failure;
     672             :             }
     673             :         }
     674             :     }
     675             : 
     676             :     // Same for Min, Max and NoData, defined per band or per dataset
     677             :     // If they are set as null strings, they clear the server declared values
     678         348 :     if (ret == CE_None)
     679             :     {
     680             :         // Data values are attributes, they include NoData Min and Max
     681         347 :         if (nullptr != CPLGetXMLNode(config, "DataValues"))
     682             :         {
     683             :             const char *nodata =
     684           3 :                 CPLGetXMLValue(config, "DataValues.NoData", "");
     685           3 :             if (strlen(nodata) > 0)
     686             :             {
     687           3 :                 SetTileOO("@NDV", nodata);
     688           3 :                 WMSSetNoDataValue(nodata);
     689             :             }
     690           3 :             const char *min = CPLGetXMLValue(config, "DataValues.min", nullptr);
     691           3 :             if (min != nullptr)
     692           0 :                 WMSSetMinValue(min);
     693           3 :             const char *max = CPLGetXMLValue(config, "DataValues.max", nullptr);
     694           3 :             if (max != nullptr)
     695           0 :                 WMSSetMaxValue(max);
     696             :         }
     697             :     }
     698             : 
     699         348 :     if (ret == CE_None)
     700             :     {
     701         347 :         if (m_oSRS.IsEmpty())
     702             :         {
     703         374 :             const auto oSRS = m_mini_driver->GetSpatialRef();
     704         187 :             if (!oSRS.IsEmpty())
     705             :             {
     706           6 :                 m_oSRS = oSRS;
     707             :             }
     708             :         }
     709             :     }
     710             : 
     711             :     // Finish the minidriver initialization
     712         348 :     if (ret == CE_None)
     713         347 :         m_mini_driver->EndInit();
     714             : 
     715         348 :     return ret;
     716             : }
     717             : 
     718             : /************************************************************************/
     719             : /*                             IRasterIO()                              */
     720             : /************************************************************************/
     721           6 : CPLErr GDALWMSDataset::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
     722             :                                  void *buffer, int bsx, int bsy,
     723             :                                  GDALDataType bdt, int band_count,
     724             :                                  BANDMAP_TYPE band_map, GSpacing nPixelSpace,
     725             :                                  GSpacing nLineSpace, GSpacing nBandSpace,
     726             :                                  GDALRasterIOExtraArg *psExtraArg)
     727             : {
     728             :     CPLErr ret;
     729             : 
     730           6 :     if (rw != GF_Read)
     731           0 :         return CE_Failure;
     732           6 :     if (buffer == nullptr)
     733           0 :         return CE_Failure;
     734           6 :     if ((sx == 0) || (sy == 0) || (bsx == 0) || (bsy == 0) || (band_count == 0))
     735           0 :         return CE_None;
     736             : 
     737           6 :     m_hint.m_x0 = x0;
     738           6 :     m_hint.m_y0 = y0;
     739           6 :     m_hint.m_sx = sx;
     740           6 :     m_hint.m_sy = sy;
     741           6 :     m_hint.m_overview = -1;
     742           6 :     m_hint.m_valid = true;
     743             :     // printf("[%p] GDALWMSDataset::IRasterIO(x0: %d, y0: %d, sx: %d, sy: %d,
     744             :     // bsx: %d, bsy: %d, band_count: %d, band_map: %p)\n", this, x0, y0, sx, sy,
     745             :     // bsx, bsy, band_count, band_map);
     746           6 :     ret = GDALDataset::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt,
     747             :                                  band_count, band_map, nPixelSpace, nLineSpace,
     748             :                                  nBandSpace, psExtraArg);
     749           6 :     m_hint.m_valid = false;
     750             : 
     751           6 :     return ret;
     752             : }
     753             : 
     754             : /************************************************************************/
     755             : /*                          GetSpatialRef()                             */
     756             : /************************************************************************/
     757          88 : const OGRSpatialReference *GDALWMSDataset::GetSpatialRef() const
     758             : {
     759          88 :     return m_oSRS.IsEmpty() ? nullptr : &m_oSRS;
     760             : }
     761             : 
     762             : /************************************************************************/
     763             : /*                           SetSpatialRef()                            */
     764             : /************************************************************************/
     765           0 : CPLErr GDALWMSDataset::SetSpatialRef(const OGRSpatialReference *)
     766             : {
     767           0 :     return CE_Failure;
     768             : }
     769             : 
     770             : /************************************************************************/
     771             : /*                          GetGeoTransform()                           */
     772             : /************************************************************************/
     773         172 : CPLErr GDALWMSDataset::GetGeoTransform(double *gt)
     774             : {
     775         172 :     if (!(m_mini_driver_caps.m_has_geotransform))
     776             :     {
     777           0 :         gt[0] = 0;
     778           0 :         gt[1] = 1;
     779           0 :         gt[2] = 0;
     780           0 :         gt[3] = 0;
     781           0 :         gt[4] = 0;
     782           0 :         gt[5] = 1;
     783           0 :         return CE_Failure;
     784             :     }
     785         172 :     gt[0] = m_data_window.m_x0;
     786         172 :     gt[1] = (m_data_window.m_x1 - m_data_window.m_x0) /
     787         172 :             static_cast<double>(m_data_window.m_sx);
     788         172 :     gt[2] = 0.0;
     789         172 :     gt[3] = m_data_window.m_y0;
     790         172 :     gt[4] = 0.0;
     791         172 :     gt[5] = (m_data_window.m_y1 - m_data_window.m_y0) /
     792         172 :             static_cast<double>(m_data_window.m_sy);
     793         172 :     return CE_None;
     794             : }
     795             : 
     796             : /************************************************************************/
     797             : /*                          SetGeoTransform()                           */
     798             : /************************************************************************/
     799           0 : CPLErr GDALWMSDataset::SetGeoTransform(CPL_UNUSED double *gt)
     800             : {
     801           0 :     return CE_Failure;
     802             : }
     803             : 
     804             : /************************************************************************/
     805             : /*                             AdviseRead()                             */
     806             : /************************************************************************/
     807           8 : CPLErr GDALWMSDataset::AdviseRead(int x0, int y0, int sx, int sy, int bsx,
     808             :                                   int bsy, GDALDataType bdt,
     809             :                                   CPL_UNUSED int band_count,
     810             :                                   CPL_UNUSED int *band_map, char **options)
     811             : {
     812             :     //    printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
     813           8 :     if (m_offline_mode || !m_use_advise_read)
     814           8 :         return CE_None;
     815           0 :     if (m_cache == nullptr)
     816           0 :         return CE_Failure;
     817             : 
     818           0 :     GDALRasterBand *band = GetRasterBand(1);
     819           0 :     if (band == nullptr)
     820           0 :         return CE_Failure;
     821           0 :     return band->AdviseRead(x0, y0, sx, sy, bsx, bsy, bdt, options);
     822             : }
     823             : 
     824             : /************************************************************************/
     825             : /*                      GetMetadataDomainList()                         */
     826             : /************************************************************************/
     827             : 
     828           0 : char **GDALWMSDataset::GetMetadataDomainList()
     829             : {
     830           0 :     return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
     831           0 :                                    TRUE, "WMS", nullptr);
     832             : }
     833             : 
     834             : /************************************************************************/
     835             : /*                          GetMetadataItem()                           */
     836             : /************************************************************************/
     837         336 : const char *GDALWMSDataset::GetMetadataItem(const char *pszName,
     838             :                                             const char *pszDomain)
     839             : {
     840         336 :     if (pszName != nullptr && EQUAL(pszName, "XML") && pszDomain != nullptr &&
     841           3 :         EQUAL(pszDomain, "WMS"))
     842             :     {
     843           3 :         return (m_osXML.size()) ? m_osXML.c_str() : nullptr;
     844             :     }
     845             : 
     846         333 :     return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
     847             : }
     848             : 
     849             : // Builds a CSL of options or returns the previous one
     850          38 : const char *const *GDALWMSDataset::GetHTTPRequestOpts()
     851             : {
     852          38 :     if (m_http_options != nullptr)
     853           5 :         return m_http_options;
     854             : 
     855          33 :     char **opts = nullptr;
     856          33 :     if (m_http_timeout != -1)
     857          33 :         opts = CSLAddString(opts, CPLOPrintf("TIMEOUT=%d", m_http_timeout));
     858             : 
     859          33 :     if (!m_osUserAgent.empty())
     860           0 :         opts = CSLAddNameValue(opts, "USERAGENT", m_osUserAgent);
     861             :     else
     862          33 :         opts = CSLAddString(
     863             :             opts,
     864             :             "USERAGENT=GDAL WMS driver (http://www.gdal.org/frmt_wms.html)");
     865             : 
     866          33 :     if (!m_osReferer.empty())
     867           0 :         opts = CSLAddNameValue(opts, "REFERER", m_osReferer);
     868             : 
     869          33 :     if (m_unsafeSsl >= 1)
     870          11 :         opts = CSLAddString(opts, "UNSAFESSL=1");
     871             : 
     872          33 :     if (!m_osUserPwd.empty())
     873           0 :         opts = CSLAddNameValue(opts, "USERPWD", m_osUserPwd);
     874             : 
     875          33 :     if (m_http_max_conn > 0)
     876          33 :         opts = CSLAddString(opts, CPLOPrintf("MAXCONN=%d", m_http_max_conn));
     877             : 
     878          33 :     if (!m_osAccept.empty())
     879           1 :         opts = CSLAddNameValue(opts, "ACCEPT", m_osAccept.c_str());
     880             : 
     881          33 :     m_http_options = opts;
     882          33 :     return m_http_options;
     883             : }
     884             : 
     885           6 : void GDALWMSDataset::SetTileOO(const char *pszName, const char *pszValue)
     886             : {
     887           6 :     if (pszName == nullptr || strlen(pszName) == 0)
     888           0 :         return;
     889           6 :     int oldidx = CSLFindName(m_tileOO, pszName);
     890           6 :     if (oldidx >= 0)
     891           0 :         m_tileOO = CSLRemoveStrings(m_tileOO, oldidx, 1, nullptr);
     892           6 :     if (pszValue != nullptr && strlen(pszValue))
     893           6 :         m_tileOO = CSLAddNameValue(m_tileOO, pszName, pszValue);
     894             : }

Generated by: LCOV version 1.14