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 63720 : int WMSDriverIdentify(GDALOpenInfo *poOpenInfo) 27 : 28 : { 29 63720 : const char *pszFilename = poOpenInfo->pszFilename; 30 63720 : const char *pabyHeader = 31 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 32 63720 : if (poOpenInfo->nHeaderBytes == 0 && 33 57444 : STARTS_WITH_CI(pszFilename, "<GDAL_WMS>")) 34 : { 35 670 : return TRUE; 36 : } 37 63050 : else if (poOpenInfo->nHeaderBytes >= 10 && 38 6130 : STARTS_WITH_CI(pabyHeader, "<GDAL_WMS>")) 39 : { 40 21 : return TRUE; 41 : } 42 119803 : else if (poOpenInfo->nHeaderBytes == 0 && 43 56774 : (STARTS_WITH_CI(pszFilename, "WMS:") || 44 119801 : CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos)) 45 : { 46 2 : return TRUE; 47 : } 48 182826 : else if (poOpenInfo->nHeaderBytes == 0 && 49 63048 : poOpenInfo->IsSingleAllowedDriver("WMS") && 50 21 : (STARTS_WITH(poOpenInfo->pszFilename, "http://") || 51 19 : STARTS_WITH(poOpenInfo->pszFilename, "https://"))) 52 : { 53 2 : return true; 54 : } 55 63025 : else if (poOpenInfo->nHeaderBytes != 0 && 56 6255 : (strstr(pabyHeader, "<WMT_MS_Capabilities") != nullptr || 57 6255 : strstr(pabyHeader, "<WMS_Capabilities") != nullptr || 58 6255 : strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != nullptr)) 59 : { 60 0 : return TRUE; 61 : } 62 63025 : else if (poOpenInfo->nHeaderBytes != 0 && 63 6255 : strstr(pabyHeader, "<WMS_Tile_Service") != nullptr) 64 : { 65 4 : return TRUE; 66 : } 67 63021 : else if (poOpenInfo->nHeaderBytes != 0 && 68 6251 : strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != nullptr) 69 : { 70 0 : return TRUE; 71 : } 72 63021 : else if (poOpenInfo->nHeaderBytes != 0 && 73 6251 : strstr(pabyHeader, "<Services") != nullptr && 74 0 : strstr(pabyHeader, "<TileMapService version=\"1.0") != nullptr) 75 : { 76 0 : return TRUE; 77 : } 78 63021 : else if (poOpenInfo->nHeaderBytes != 0 && 79 6251 : strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != nullptr) 80 : { 81 0 : return TRUE; 82 : } 83 63021 : else if (poOpenInfo->nHeaderBytes == 0 && 84 56770 : STARTS_WITH_CI(pszFilename, "http") && 85 23 : (strstr(pszFilename, "/MapServer?f=json") != nullptr || 86 21 : strstr(pszFilename, "/MapServer/?f=json") != nullptr || 87 21 : strstr(pszFilename, "/ImageServer?f=json") != nullptr || 88 21 : strstr(pszFilename, "/ImageServer/?f=json") != nullptr)) 89 : { 90 2 : return TRUE; 91 : } 92 63019 : else if (poOpenInfo->nHeaderBytes == 0 && 93 56768 : STARTS_WITH_CI(pszFilename, "AGS:")) 94 : { 95 0 : return TRUE; 96 : } 97 63019 : else if (poOpenInfo->nHeaderBytes == 0 && 98 56768 : STARTS_WITH_CI(pszFilename, "IIP:")) 99 : { 100 2 : return TRUE; 101 : } 102 63017 : else if (poOpenInfo->nHeaderBytes == 0 && 103 56766 : STARTS_WITH_CI(pszFilename, "IIIF:")) 104 : { 105 8 : return TRUE; 106 : } 107 : else 108 63009 : 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 : m_pathComponent.erase( 144 12 : CPLString(m_pathComponent).ifind(m_subdatasetComponent), 145 12 : m_subdatasetComponent.length()); 146 6 : m_pathComponent.erase(0, 4); 147 6 : const std::size_t nDoubleAndPos = m_pathComponent.find("&&"); 148 6 : if (nDoubleAndPos != std::string::npos) 149 : { 150 2 : m_pathComponent.erase(nDoubleAndPos, 1); 151 : } 152 : // Reconstruct URL with LAYERS at the end or ModifyPathComponent will fail 153 12 : m_fileName = m_driverPrefixComponent + ":" + m_pathComponent + "&" + 154 12 : m_subdatasetComponent; 155 : } 156 : } 157 : 158 2775 : static GDALSubdatasetInfo *WMSDriverGetSubdatasetInfo(const char *pszFileName) 159 : { 160 2775 : if (STARTS_WITH(pszFileName, "WMS:")) 161 : { 162 : std::unique_ptr<GDALSubdatasetInfo> info = 163 8 : std::make_unique<WMSDriverSubdatasetInfo>(pszFileName); 164 22 : if (!info->GetSubdatasetComponent().empty() && 165 14 : !info->GetPathComponent().empty()) 166 : { 167 6 : return info.release(); 168 : } 169 : } 170 2769 : return nullptr; 171 : } 172 : 173 : /************************************************************************/ 174 : /* WMSDriverSetCommonMetadata() */ 175 : /************************************************************************/ 176 : 177 1815 : void WMSDriverSetCommonMetadata(GDALDriver *poDriver) 178 : { 179 1815 : poDriver->SetDescription(DRIVER_NAME); 180 1815 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 181 1815 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service"); 182 1815 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/wms.html"); 183 1815 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 184 1815 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); 185 : 186 1815 : poDriver->pfnIdentify = WMSDriverIdentify; 187 1815 : poDriver->pfnGetSubdatasetInfoFunc = WMSDriverGetSubdatasetInfo; 188 1815 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 189 1815 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); 190 1815 : } 191 : 192 : /************************************************************************/ 193 : /* DeclareDeferredWMSPlugin() */ 194 : /************************************************************************/ 195 : 196 : #ifdef PLUGIN_FILENAME 197 2068 : void DeclareDeferredWMSPlugin() 198 : { 199 2068 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 200 : { 201 263 : return; 202 : } 203 1805 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 204 : #ifdef PLUGIN_INSTALLATION_MESSAGE 205 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 206 : PLUGIN_INSTALLATION_MESSAGE); 207 : #endif 208 1805 : WMSDriverSetCommonMetadata(poDriver); 209 1805 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 210 : } 211 : #endif