Coverage Report

Created: 2026-05-16 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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