/src/gdal/frmts/wms/wmsdrivercore.cpp
Line | Count | Source |
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 | | int WMSDriverIdentify(GDALOpenInfo *poOpenInfo) |
27 | | |
28 | 581k | { |
29 | 581k | const char *pszFilename = poOpenInfo->pszFilename; |
30 | 581k | const char *pabyHeader = |
31 | 581k | reinterpret_cast<const char *>(poOpenInfo->pabyHeader); |
32 | 581k | if (poOpenInfo->nHeaderBytes == 0 && |
33 | 486k | STARTS_WITH_CI(pszFilename, "<GDAL_WMS>")) |
34 | 538 | { |
35 | 538 | return TRUE; |
36 | 538 | } |
37 | 581k | else if (poOpenInfo->nHeaderBytes >= 10 && |
38 | 94.7k | STARTS_WITH_CI(pabyHeader, "<GDAL_WMS>")) |
39 | 0 | { |
40 | 0 | return TRUE; |
41 | 0 | } |
42 | 581k | else if (poOpenInfo->nHeaderBytes == 0 && |
43 | 486k | (STARTS_WITH_CI(pszFilename, "WMS:") || |
44 | 485k | CPLString(pszFilename).ifind("SERVICE=WMS") != std::string::npos)) |
45 | 155k | { |
46 | 155k | return TRUE; |
47 | 155k | } |
48 | 425k | else if (poOpenInfo->nHeaderBytes == 0 && |
49 | 330k | poOpenInfo->IsSingleAllowedDriver("WMS") && |
50 | 0 | (STARTS_WITH(poOpenInfo->pszFilename, "http://") || |
51 | 0 | STARTS_WITH(poOpenInfo->pszFilename, "https://"))) |
52 | 0 | { |
53 | 0 | return true; |
54 | 0 | } |
55 | 425k | else if (poOpenInfo->nHeaderBytes != 0 && |
56 | 94.9k | (strstr(pabyHeader, "<WMT_MS_Capabilities") != nullptr || |
57 | 94.8k | strstr(pabyHeader, "<WMS_Capabilities") != nullptr || |
58 | 94.4k | strstr(pabyHeader, "<!DOCTYPE WMT_MS_Capabilities") != nullptr)) |
59 | 1.47k | { |
60 | 1.47k | return TRUE; |
61 | 1.47k | } |
62 | 424k | else if (poOpenInfo->nHeaderBytes != 0 && |
63 | 93.4k | strstr(pabyHeader, "<WMS_Tile_Service") != nullptr) |
64 | 662 | { |
65 | 662 | return TRUE; |
66 | 662 | } |
67 | 423k | else if (poOpenInfo->nHeaderBytes != 0 && |
68 | 92.7k | strstr(pabyHeader, "<TileMap version=\"1.0.0\"") != nullptr) |
69 | 344 | { |
70 | 344 | return TRUE; |
71 | 344 | } |
72 | 423k | else if (poOpenInfo->nHeaderBytes != 0 && |
73 | 92.4k | strstr(pabyHeader, "<Services") != nullptr && |
74 | 60 | strstr(pabyHeader, "<TileMapService version=\"1.0") != nullptr) |
75 | 0 | { |
76 | 0 | return TRUE; |
77 | 0 | } |
78 | 423k | else if (poOpenInfo->nHeaderBytes != 0 && |
79 | 92.4k | strstr(pabyHeader, "<TileMapService version=\"1.0.0\"") != nullptr) |
80 | 166 | { |
81 | 166 | return TRUE; |
82 | 166 | } |
83 | 422k | else if (poOpenInfo->nHeaderBytes == 0 && |
84 | 422k | STARTS_WITH_CI(pszFilename, "http") && |
85 | 442 | (strstr(pszFilename, "/MapServer?f=json") != nullptr || |
86 | 442 | strstr(pszFilename, "/MapServer/?f=json") != nullptr || |
87 | 442 | strstr(pszFilename, "/ImageServer?f=json") != nullptr || |
88 | 442 | strstr(pszFilename, "/ImageServer/?f=json") != nullptr)) |
89 | 0 | { |
90 | 0 | return TRUE; |
91 | 0 | } |
92 | 422k | else if (poOpenInfo->nHeaderBytes == 0 && |
93 | 330k | STARTS_WITH_CI(pszFilename, "AGS:")) |
94 | 0 | { |
95 | 0 | return TRUE; |
96 | 0 | } |
97 | 422k | else if (poOpenInfo->nHeaderBytes == 0 && |
98 | 330k | STARTS_WITH_CI(pszFilename, "IIP:")) |
99 | 0 | { |
100 | 0 | return TRUE; |
101 | 0 | } |
102 | 422k | else if (poOpenInfo->nHeaderBytes == 0 && |
103 | 330k | STARTS_WITH_CI(pszFilename, "IIIF:")) |
104 | 0 | { |
105 | 0 | return TRUE; |
106 | 0 | } |
107 | 422k | else |
108 | 422k | return FALSE; |
109 | 581k | } |
110 | | |
111 | | /************************************************************************/ |
112 | | /* OGRWMSDriverGetSubdatasetInfo() */ |
113 | | /************************************************************************/ |
114 | | |
115 | | struct WMSDriverSubdatasetInfo final : public GDALSubdatasetInfo |
116 | | { |
117 | | public: |
118 | | explicit WMSDriverSubdatasetInfo(const std::string &fileName) |
119 | 22 | : GDALSubdatasetInfo(fileName) |
120 | 22 | { |
121 | 22 | } |
122 | | |
123 | | // GDALSubdatasetInfo interface |
124 | | private: |
125 | | void parseFileName() override; |
126 | | }; |
127 | | |
128 | | void WMSDriverSubdatasetInfo::parseFileName() |
129 | 22 | { |
130 | 22 | if (!STARTS_WITH_CI(m_fileName.c_str(), "WMS:")) |
131 | 0 | { |
132 | 0 | return; |
133 | 0 | } |
134 | | |
135 | 22 | const CPLString osLayers = CPLURLGetValue(m_fileName.c_str(), "LAYERS"); |
136 | | |
137 | 22 | if (!osLayers.empty()) |
138 | 18 | { |
139 | 18 | m_subdatasetComponent = "LAYERS=" + osLayers; |
140 | 18 | m_driverPrefixComponent = "WMS"; |
141 | | |
142 | 18 | m_pathComponent = m_fileName; |
143 | 18 | m_pathComponent.erase( |
144 | 18 | CPLString(m_pathComponent).ifind(m_subdatasetComponent), |
145 | 18 | m_subdatasetComponent.length()); |
146 | 18 | m_pathComponent.erase(0, 4); |
147 | 18 | const std::size_t nDoubleAndPos = m_pathComponent.find("&&"); |
148 | 18 | if (nDoubleAndPos != std::string::npos) |
149 | 16 | { |
150 | 16 | m_pathComponent.erase(nDoubleAndPos, 1); |
151 | 16 | } |
152 | | // Reconstruct URL with LAYERS at the end or ModifyPathComponent will fail |
153 | 18 | m_fileName = m_driverPrefixComponent + ":" + m_pathComponent + "&" + |
154 | 18 | m_subdatasetComponent; |
155 | 18 | } |
156 | 22 | } |
157 | | |
158 | | static GDALSubdatasetInfo *WMSDriverGetSubdatasetInfo(const char *pszFileName) |
159 | 5.61k | { |
160 | 5.61k | if (STARTS_WITH(pszFileName, "WMS:")) |
161 | 22 | { |
162 | 22 | std::unique_ptr<GDALSubdatasetInfo> info = |
163 | 22 | std::make_unique<WMSDriverSubdatasetInfo>(pszFileName); |
164 | 22 | if (!info->GetSubdatasetComponent().empty() && |
165 | 18 | !info->GetPathComponent().empty()) |
166 | 18 | { |
167 | 18 | return info.release(); |
168 | 18 | } |
169 | 22 | } |
170 | 5.59k | return nullptr; |
171 | 5.61k | } |
172 | | |
173 | | /************************************************************************/ |
174 | | /* WMSDriverSetCommonMetadata() */ |
175 | | /************************************************************************/ |
176 | | |
177 | | void WMSDriverSetCommonMetadata(GDALDriver *poDriver) |
178 | 22 | { |
179 | 22 | poDriver->SetDescription(DRIVER_NAME); |
180 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); |
181 | 22 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service"); |
182 | 22 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/wms.html"); |
183 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
184 | 22 | poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); |
185 | | |
186 | 22 | poDriver->pfnIdentify = WMSDriverIdentify; |
187 | 22 | poDriver->pfnGetSubdatasetInfoFunc = WMSDriverGetSubdatasetInfo; |
188 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); |
189 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); |
190 | 22 | } |
191 | | |
192 | | /************************************************************************/ |
193 | | /* DeclareDeferredWMSPlugin() */ |
194 | | /************************************************************************/ |
195 | | |
196 | | #ifdef PLUGIN_FILENAME |
197 | | void DeclareDeferredWMSPlugin() |
198 | | { |
199 | | if (GDALGetDriverByName(DRIVER_NAME) != nullptr) |
200 | | { |
201 | | return; |
202 | | } |
203 | | 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 | | WMSDriverSetCommonMetadata(poDriver); |
209 | | GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); |
210 | | } |
211 | | #endif |