Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements OGRVRTDriver class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2009-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "ogr_vrt.h"
32 :
33 : #include <cctype>
34 : #include <cstddef>
35 : #include <cstdio>
36 : #include <cstring>
37 : #include <memory>
38 : #include <vector>
39 :
40 : #include "cpl_conv.h"
41 : #include "cpl_error.h"
42 : #include "cpl_minixml.h"
43 : #include "cpl_string.h"
44 : #include "cpl_vsi.h"
45 : #include "gdal.h"
46 : #include "gdal_priv.h"
47 :
48 : /************************************************************************/
49 : /* OGRVRTErrorHandler() */
50 : /************************************************************************/
51 :
52 68 : static void CPL_STDCALL OGRVRTErrorHandler(CPL_UNUSED CPLErr eErr,
53 : CPL_UNUSED CPLErrorNum nType,
54 : const char *pszMsg)
55 : {
56 : std::vector<CPLString> *paosErrors =
57 68 : static_cast<std::vector<CPLString> *>(CPLGetErrorHandlerUserData());
58 68 : paosErrors->push_back(pszMsg);
59 68 : }
60 :
61 : /************************************************************************/
62 : /* OGRVRTDriverIdentify() */
63 : /************************************************************************/
64 :
65 46531 : static int OGRVRTDriverIdentify(GDALOpenInfo *poOpenInfo)
66 : {
67 46531 : if (!poOpenInfo->bStatOK)
68 : {
69 : // Are we being passed the XML definition directly?
70 : // Skip any leading spaces/blanks.
71 40535 : const char *pszTestXML = poOpenInfo->pszFilename;
72 40566 : while (*pszTestXML != '\0' &&
73 39781 : isspace(static_cast<unsigned char>(*pszTestXML)))
74 31 : pszTestXML++;
75 40535 : if (STARTS_WITH_CI(pszTestXML, "<OGRVRTDataSource>"))
76 : {
77 106 : return TRUE;
78 : }
79 40429 : return FALSE;
80 : }
81 :
82 11292 : return poOpenInfo->fpL != nullptr &&
83 5296 : strstr(reinterpret_cast<char *>(poOpenInfo->pabyHeader),
84 5996 : "<OGRVRTDataSource") != nullptr;
85 : }
86 :
87 : /************************************************************************/
88 : /* Open() */
89 : /************************************************************************/
90 :
91 402 : static GDALDataset *OGRVRTDriverOpen(GDALOpenInfo *poOpenInfo)
92 :
93 : {
94 : #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
95 402 : if (!OGRVRTDriverIdentify(poOpenInfo))
96 0 : return nullptr;
97 : #endif
98 :
99 : // Are we being passed the XML definition directly?
100 : // Skip any leading spaces/blanks.
101 402 : const char *pszTestXML = poOpenInfo->pszFilename;
102 413 : while (*pszTestXML != '\0' &&
103 413 : isspace(static_cast<unsigned char>(*pszTestXML)))
104 11 : pszTestXML++;
105 :
106 402 : char *pszXML = nullptr;
107 402 : if (STARTS_WITH_CI(pszTestXML, "<OGRVRTDataSource>"))
108 : {
109 53 : pszXML = CPLStrdup(pszTestXML);
110 : }
111 :
112 : // Open file and check if it contains appropriate XML.
113 : else
114 : {
115 : #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
116 : if (poOpenInfo->fpL == nullptr)
117 : return nullptr;
118 : #endif
119 : VSIStatBufL sStatBuf;
120 349 : if (VSIStatL(poOpenInfo->pszFilename, &sStatBuf) != 0)
121 : {
122 0 : return nullptr;
123 : }
124 349 : if (sStatBuf.st_size > 10 * 1024 * 1024 &&
125 0 : !CPLTestBool(CPLGetConfigOption("OGR_VRT_FORCE_LOADING", "NO")))
126 : {
127 0 : CPLError(CE_Failure, CPLE_AppDefined,
128 : "Suscipicously long VRT file. If you really want to "
129 : "open it, define OGR_VRT_FORCE_LOADING=YES as "
130 : "configuration option");
131 0 : return nullptr;
132 : }
133 :
134 : // It is the right file, now load the full XML definition.
135 349 : const int nLen = static_cast<int>(sStatBuf.st_size);
136 :
137 349 : pszXML = static_cast<char *>(VSI_MALLOC_VERBOSE(nLen + 1));
138 349 : if (pszXML == nullptr)
139 0 : return nullptr;
140 :
141 349 : pszXML[nLen] = '\0';
142 349 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
143 349 : if (static_cast<int>(VSIFReadL(pszXML, 1, nLen, poOpenInfo->fpL)) !=
144 : nLen)
145 : {
146 0 : CPLFree(pszXML);
147 0 : return nullptr;
148 : }
149 349 : VSIFCloseL(poOpenInfo->fpL);
150 349 : poOpenInfo->fpL = nullptr;
151 : }
152 :
153 : // Parse the XML.
154 402 : CPLXMLNode *psTree = CPLParseXMLString(pszXML);
155 :
156 402 : if (psTree == nullptr)
157 : {
158 1 : CPLFree(pszXML);
159 1 : return nullptr;
160 : }
161 :
162 : // XML Validation.
163 401 : if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES")))
164 : {
165 401 : const char *pszXSD = CPLFindFile("gdal", "ogrvrt.xsd");
166 401 : if (pszXSD != nullptr)
167 : {
168 802 : std::vector<CPLString> aosErrors;
169 401 : CPLPushErrorHandlerEx(OGRVRTErrorHandler, &aosErrors);
170 401 : const int bRet = CPLValidateXML(pszXML, pszXSD, nullptr);
171 401 : CPLPopErrorHandler();
172 401 : if (!bRet)
173 : {
174 110 : if (!aosErrors.empty() &&
175 55 : strstr(aosErrors[0].c_str(), "missing libxml2 support") ==
176 : nullptr)
177 : {
178 118 : for (size_t i = 0; i < aosErrors.size(); i++)
179 : {
180 63 : CPLError(CE_Warning, CPLE_AppDefined, "%s",
181 63 : aosErrors[i].c_str());
182 : }
183 : }
184 : }
185 401 : CPLErrorReset();
186 : }
187 : }
188 401 : CPLFree(pszXML);
189 :
190 : // Create a virtual datasource configured based on this XML input.
191 : OGRVRTDataSource *poDS = new OGRVRTDataSource(
192 401 : static_cast<GDALDriver *>(GDALGetDriverByName("OGR_VRT")));
193 :
194 : // psTree is owned by poDS.
195 401 : if (!poDS->Initialize(psTree, poOpenInfo->pszFilename,
196 401 : poOpenInfo->eAccess == GA_Update))
197 : {
198 1 : delete poDS;
199 1 : return nullptr;
200 : }
201 :
202 400 : return poDS;
203 : }
204 :
205 : /************************************************************************/
206 : /* RegisterOGRVRT() */
207 : /************************************************************************/
208 :
209 1512 : void RegisterOGRVRT()
210 :
211 : {
212 1512 : if (GDALGetDriverByName("OGR_VRT") != nullptr)
213 295 : return;
214 :
215 1217 : GDALDriver *poDriver = new GDALDriver();
216 :
217 1217 : poDriver->SetDescription("OGR_VRT");
218 1217 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
219 1217 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "VRT - Virtual Datasource");
220 1217 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "vrt");
221 1217 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/vrt.html");
222 1217 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
223 1217 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES, "YES");
224 1217 : poDriver->SetMetadataItem(GDAL_DCAP_FEATURE_STYLES_READ, "YES");
225 1217 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
226 1217 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
227 1217 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES");
228 1217 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
229 1217 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
230 :
231 1217 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
232 : "WidthPrecision Nullable Unique Default "
233 1217 : "Comment AlternativeName");
234 :
235 1217 : poDriver->pfnOpen = OGRVRTDriverOpen;
236 1217 : poDriver->pfnIdentify = OGRVRTDriverIdentify;
237 :
238 1217 : GetGDALDriverManager()->RegisterDriver(poDriver);
239 : }
|