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 61049 : int WMSDriverIdentify(GDALOpenInfo *poOpenInfo) 27 : 28 : { 29 61049 : const char *pszFilename = poOpenInfo->pszFilename; 30 61049 : const char *pabyHeader = 31 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 32 61049 : if (poOpenInfo->nHeaderBytes == 0 && 33 56246 : STARTS_WITH_CI(pszFilename, "<GDAL_WMS>")) 34 : { 35 668 : return TRUE; 36 : } 37 60381 : else if (poOpenInfo->nHeaderBytes >= 10 && 38 4661 : STARTS_WITH_CI(pabyHeader, "<GDAL_WMS>")) 39 : { 40 21 : return TRUE; 41 : } 42 115938 : else if (poOpenInfo->nHeaderBytes == 0 && 43 55578 : (STARTS_WITH_CI(pszFilename, "WMS:") || 44 115936 : CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos)) 45 : { 46 2 : return TRUE; 47 : } 48 176292 : else if (poOpenInfo->nHeaderBytes == 0 && 49 60379 : poOpenInfo->IsSingleAllowedDriver("WMS") && 50 21 : (STARTS_WITH(poOpenInfo->pszFilename, "http://") || 51 19 : STARTS_WITH(poOpenInfo->pszFilename, "https://"))) 52 : { 53 2 : return true; 54 : } 55 60356 : else if (poOpenInfo->nHeaderBytes != 0 && 56 4782 : (strstr(pabyHeader, "<WMT_MS_Capabilities") != nullptr || 57 4782 : strstr(pabyHeader, "<WMS_Capabilities") != nullptr || 58 4782 : strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != nullptr)) 59 : { 60 0 : return TRUE; 61 : } 62 60356 : else if (poOpenInfo->nHeaderBytes != 0 && 63 4782 : strstr(pabyHeader, "<WMS_Tile_Service") != nullptr) 64 : { 65 4 : return TRUE; 66 : } 67 60352 : else if (poOpenInfo->nHeaderBytes != 0 && 68 4778 : strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != nullptr) 69 : { 70 0 : return TRUE; 71 : } 72 60352 : else if (poOpenInfo->nHeaderBytes != 0 && 73 4778 : strstr(pabyHeader, "<Services") != nullptr && 74 0 : strstr(pabyHeader, "<TileMapService version=\"1.0") != nullptr) 75 : { 76 0 : return TRUE; 77 : } 78 60352 : else if (poOpenInfo->nHeaderBytes != 0 && 79 4778 : strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != nullptr) 80 : { 81 0 : return TRUE; 82 : } 83 60352 : else if (poOpenInfo->nHeaderBytes == 0 && 84 55574 : 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 60350 : else if (poOpenInfo->nHeaderBytes == 0 && 93 55572 : STARTS_WITH_CI(pszFilename, "AGS:")) 94 : { 95 0 : return TRUE; 96 : } 97 60350 : else if (poOpenInfo->nHeaderBytes == 0 && 98 55572 : STARTS_WITH_CI(pszFilename, "IIP:")) 99 : { 100 2 : return TRUE; 101 : } 102 60348 : else if (poOpenInfo->nHeaderBytes == 0 && 103 55570 : STARTS_WITH_CI(pszFilename, "IIIF:")) 104 : { 105 8 : return TRUE; 106 : } 107 : else 108 60340 : 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 1767 : void WMSDriverSetCommonMetadata(GDALDriver *poDriver) 177 : { 178 1767 : poDriver->SetDescription(DRIVER_NAME); 179 1767 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 180 1767 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service"); 181 1767 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/wms.html"); 182 1767 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 183 1767 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 184 : 185 1767 : poDriver->pfnIdentify = WMSDriverIdentify; 186 1767 : poDriver->pfnGetSubdatasetInfoFunc = WMSDriverGetSubdatasetInfo; 187 1767 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 188 1767 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 189 1767 : } 190 : 191 : /************************************************************************/ 192 : /* DeclareDeferredWMSPlugin() */ 193 : /************************************************************************/ 194 : 195 : #ifdef PLUGIN_FILENAME 196 2040 : void DeclareDeferredWMSPlugin() 197 : { 198 2040 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 199 : { 200 283 : return; 201 : } 202 1757 : 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 1757 : WMSDriverSetCommonMetadata(poDriver); 208 1757 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 209 : } 210 : #endif