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) 2009-2014, Even Rouault <even dot rouault at spatialys.com> 11 : * 12 : * SPDX-License-Identifier: MIT 13 : ****************************************************************************/ 14 : 15 : #include "gdal_frmts.h" 16 : #include "gdalplugindriverproxy.h" 17 : 18 : #include "wmsdrivercore.h" 19 : 20 : #include "gdalsubdatasetinfo.h" 21 : 22 : /************************************************************************/ 23 : /* WMSDriverIdentify() */ 24 : /************************************************************************/ 25 : 26 60440 : int WMSDriverIdentify(GDALOpenInfo *poOpenInfo) 27 : 28 : { 29 60440 : const char *pszFilename = poOpenInfo->pszFilename; 30 60440 : const char *pabyHeader = 31 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 32 60440 : if (poOpenInfo->nHeaderBytes == 0 && 33 55677 : STARTS_WITH_CI(pszFilename, "<GDAL_WMS>")) 34 : { 35 670 : return TRUE; 36 : } 37 59770 : else if (poOpenInfo->nHeaderBytes >= 10 && 38 4621 : STARTS_WITH_CI(pabyHeader, "<GDAL_WMS>")) 39 : { 40 21 : return TRUE; 41 : } 42 114756 : else if (poOpenInfo->nHeaderBytes == 0 && 43 55007 : (STARTS_WITH_CI(pszFilename, "WMS:") || 44 114754 : CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos)) 45 : { 46 2 : return TRUE; 47 : } 48 174499 : else if (poOpenInfo->nHeaderBytes == 0 && 49 59768 : poOpenInfo->IsSingleAllowedDriver("WMS") && 50 21 : (STARTS_WITH(poOpenInfo->pszFilename, "http://") || 51 19 : STARTS_WITH(poOpenInfo->pszFilename, "https://"))) 52 : { 53 2 : return true; 54 : } 55 59745 : else if (poOpenInfo->nHeaderBytes != 0 && 56 4742 : (strstr(pabyHeader, "<WMT_MS_Capabilities") != nullptr || 57 4742 : strstr(pabyHeader, "<WMS_Capabilities") != nullptr || 58 4742 : strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != nullptr)) 59 : { 60 0 : return TRUE; 61 : } 62 59745 : else if (poOpenInfo->nHeaderBytes != 0 && 63 4742 : strstr(pabyHeader, "<WMS_Tile_Service") != nullptr) 64 : { 65 4 : return TRUE; 66 : } 67 59741 : else if (poOpenInfo->nHeaderBytes != 0 && 68 4738 : strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != nullptr) 69 : { 70 0 : return TRUE; 71 : } 72 59741 : else if (poOpenInfo->nHeaderBytes != 0 && 73 4738 : strstr(pabyHeader, "<Services") != nullptr && 74 0 : strstr(pabyHeader, "<TileMapService version=\"1.0") != nullptr) 75 : { 76 0 : return TRUE; 77 : } 78 59741 : else if (poOpenInfo->nHeaderBytes != 0 && 79 4738 : strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != nullptr) 80 : { 81 0 : return TRUE; 82 : } 83 59741 : else if (poOpenInfo->nHeaderBytes == 0 && 84 55003 : STARTS_WITH_CI(pszFilename, "http") && 85 20 : (strstr(pszFilename, "/MapServer?f=json") != nullptr || 86 18 : strstr(pszFilename, "/MapServer/?f=json") != nullptr || 87 18 : strstr(pszFilename, "/ImageServer?f=json") != nullptr || 88 18 : strstr(pszFilename, "/ImageServer/?f=json") != nullptr)) 89 : { 90 2 : return TRUE; 91 : } 92 59739 : else if (poOpenInfo->nHeaderBytes == 0 && 93 55001 : STARTS_WITH_CI(pszFilename, "AGS:")) 94 : { 95 0 : return TRUE; 96 : } 97 59739 : else if (poOpenInfo->nHeaderBytes == 0 && 98 55001 : STARTS_WITH_CI(pszFilename, "IIP:")) 99 : { 100 2 : return TRUE; 101 : } 102 59737 : else if (poOpenInfo->nHeaderBytes == 0 && 103 54999 : STARTS_WITH_CI(pszFilename, "IIIF:")) 104 : { 105 8 : return TRUE; 106 : } 107 : else 108 59729 : return FALSE; 109 : } 110 : 111 : /************************************************************************/ 112 : /* OGRWMSDriverGetSubdatasetInfo() */ 113 : /************************************************************************/ 114 : 115 : struct WMSDriverSubdatasetInfo final : public GDALSubdatasetInfo 116 : { 117 : public: 118 8 : explicit WMSDriverSubdatasetInfo(const std::string &fileName) 119 8 : : GDALSubdatasetInfo(fileName) 120 : { 121 8 : } 122 : 123 : // GDALSubdatasetInfo interface 124 : private: 125 : void parseFileName() override; 126 : }; 127 : 128 8 : void WMSDriverSubdatasetInfo::parseFileName() 129 : { 130 8 : if (!STARTS_WITH_CI(m_fileName.c_str(), "WMS:")) 131 : { 132 0 : return; 133 : } 134 : 135 16 : const CPLString osLayers = CPLURLGetValue(m_fileName.c_str(), "LAYERS"); 136 : 137 8 : if (!osLayers.empty()) 138 : { 139 6 : m_subdatasetComponent = "LAYERS=" + osLayers; 140 6 : m_driverPrefixComponent = "WMS"; 141 : 142 6 : m_pathComponent = m_fileName; 143 6 : m_pathComponent.erase(m_pathComponent.find(m_subdatasetComponent), 144 6 : m_subdatasetComponent.length()); 145 6 : m_pathComponent.erase(0, 4); 146 6 : const std::size_t nDoubleAndPos = m_pathComponent.find("&&"); 147 6 : if (nDoubleAndPos != std::string::npos) 148 : { 149 2 : m_pathComponent.erase(nDoubleAndPos, 1); 150 : } 151 : // Reconstruct URL with LAYERS at the end or ModifyPathComponent will fail 152 12 : m_fileName = m_driverPrefixComponent + ":" + m_pathComponent + "&" + 153 12 : m_subdatasetComponent; 154 : } 155 : } 156 : 157 2717 : static GDALSubdatasetInfo *WMSDriverGetSubdatasetInfo(const char *pszFileName) 158 : { 159 2717 : if (STARTS_WITH(pszFileName, "WMS:")) 160 : { 161 : std::unique_ptr<GDALSubdatasetInfo> info = 162 8 : std::make_unique<WMSDriverSubdatasetInfo>(pszFileName); 163 22 : if (!info->GetSubdatasetComponent().empty() && 164 14 : !info->GetPathComponent().empty()) 165 : { 166 6 : return info.release(); 167 : } 168 : } 169 2711 : return nullptr; 170 : } 171 : 172 : /************************************************************************/ 173 : /* WMSDriverSetCommonMetadata() */ 174 : /************************************************************************/ 175 : 176 1760 : void WMSDriverSetCommonMetadata(GDALDriver *poDriver) 177 : { 178 1760 : poDriver->SetDescription(DRIVER_NAME); 179 1760 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 180 1760 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service"); 181 1760 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/wms.html"); 182 1760 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 183 1760 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 184 : 185 1760 : poDriver->pfnIdentify = WMSDriverIdentify; 186 1760 : poDriver->pfnGetSubdatasetInfoFunc = WMSDriverGetSubdatasetInfo; 187 1760 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 188 1760 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 189 1760 : } 190 : 191 : /************************************************************************/ 192 : /* DeclareDeferredWMSPlugin() */ 193 : /************************************************************************/ 194 : 195 : #ifdef PLUGIN_FILENAME 196 2033 : void DeclareDeferredWMSPlugin() 197 : { 198 2033 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 199 : { 200 283 : return; 201 : } 202 1750 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 203 : #ifdef PLUGIN_INSTALLATION_MESSAGE 204 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 205 : PLUGIN_INSTALLATION_MESSAGE); 206 : #endif 207 1750 : WMSDriverSetCommonMetadata(poDriver); 208 1750 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 209 : } 210 : #endif