Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OGR
4 : * Purpose: OGRGMLDriver implementation
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "ogr_gml.h"
30 : #include "cpl_conv.h"
31 : #include "cpl_multiproc.h"
32 : #include "gmlreaderp.h"
33 :
34 : /************************************************************************/
35 : /* OGRGMLDriverIdentify() */
36 : /************************************************************************/
37 :
38 45665 : static int OGRGMLDriverIdentify(GDALOpenInfo *poOpenInfo)
39 :
40 : {
41 45665 : if (poOpenInfo->fpL == nullptr)
42 : {
43 41020 : if (strstr(poOpenInfo->pszFilename, "xsd=") != nullptr)
44 4 : return -1; /* must be later checked */
45 41016 : return FALSE;
46 : }
47 : /* Might be a OS-Mastermap gzipped GML, so let be nice and try to open */
48 : /* it transparently with /vsigzip/ */
49 9312 : else if (poOpenInfo->pabyHeader[0] == 0x1f &&
50 22 : poOpenInfo->pabyHeader[1] == 0x8b &&
51 4671 : EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "gz") &&
52 4 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsigzip/"))
53 : {
54 4 : return -1; /* must be later checked */
55 : }
56 : else
57 : {
58 4641 : const char *szPtr = (const char *)poOpenInfo->pabyHeader;
59 :
60 4641 : if (((unsigned char)szPtr[0] == 0xEF) &&
61 7 : ((unsigned char)szPtr[1] == 0xBB) &&
62 7 : ((unsigned char)szPtr[2] == 0xBF))
63 : {
64 7 : szPtr += 3;
65 : }
66 : /* --------------------------------------------------------------------
67 : */
68 : /* Here, we expect the opening chevrons of GML tree root element */
69 : /* --------------------------------------------------------------------
70 : */
71 4641 : if (szPtr[0] != '<')
72 3583 : return FALSE;
73 :
74 1058 : if (!poOpenInfo->TryToIngest(4096))
75 0 : return FALSE;
76 :
77 2116 : return OGRGMLDataSource::CheckHeader(
78 1058 : (const char *)poOpenInfo->pabyHeader);
79 : }
80 : }
81 :
82 : /************************************************************************/
83 : /* Open() */
84 : /************************************************************************/
85 :
86 398 : static GDALDataset *OGRGMLDriverOpen(GDALOpenInfo *poOpenInfo)
87 :
88 : {
89 398 : if (poOpenInfo->eAccess == GA_Update)
90 0 : return nullptr;
91 :
92 398 : if (OGRGMLDriverIdentify(poOpenInfo) == FALSE)
93 15 : return nullptr;
94 :
95 383 : OGRGMLDataSource *poDS = new OGRGMLDataSource();
96 :
97 383 : if (!poDS->Open(poOpenInfo))
98 : {
99 0 : delete poDS;
100 0 : return nullptr;
101 : }
102 : else
103 383 : return poDS;
104 : }
105 :
106 : /************************************************************************/
107 : /* Create() */
108 : /************************************************************************/
109 :
110 : static GDALDataset *
111 93 : OGRGMLDriverCreate(const char *pszName, CPL_UNUSED int nBands,
112 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
113 : CPL_UNUSED GDALDataType eDT, char **papszOptions)
114 : {
115 93 : OGRGMLDataSource *poDS = new OGRGMLDataSource();
116 :
117 93 : if (!poDS->Create(pszName, papszOptions))
118 : {
119 1 : delete poDS;
120 1 : return nullptr;
121 : }
122 : else
123 92 : return poDS;
124 : }
125 :
126 : /************************************************************************/
127 : /* RegisterOGRGML() */
128 : /************************************************************************/
129 :
130 1520 : void RegisterOGRGML()
131 :
132 : {
133 1520 : if (GDALGetDriverByName("GML") != nullptr)
134 301 : return;
135 :
136 1219 : GDALDriver *poDriver = new GDALDriver();
137 :
138 1219 : poDriver->SetDescription("GML");
139 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
140 1219 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
141 1219 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
142 1219 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES");
143 1219 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
144 1219 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
145 1219 : "Geography Markup Language (GML)");
146 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gml");
147 1219 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gml xml");
148 1219 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/gml.html");
149 1219 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
150 :
151 1219 : poDriver->SetMetadataItem(
152 : GDAL_DMD_OPENOPTIONLIST,
153 : "<OpenOptionList>"
154 : " <Option name='XSD' type='string' description='Name of the related "
155 : "application schema file (.xsd).'/>"
156 : " <Option name='GFS_TEMPLATE' type='string' description='Filename of "
157 : "a .gfs template file to apply.'/>"
158 : " <Option name='WRITE_GFS' type='string-select' description='Whether "
159 : "to write a .gfs file' default='AUTO'>"
160 : " <Value>AUTO</Value>"
161 : " <Value>YES</Value>"
162 : " <Value>NO</Value>"
163 : " </Option>"
164 : " <Option name='FORCE_SRS_DETECTION' type='boolean' "
165 : "description='Force a full scan to detect the SRS of layers.' "
166 : "default='NO'/>"
167 : " <Option name='EMPTY_AS_NULL' type='boolean' description='Force "
168 : "empty fields to be reported as NULL. Set to NO so that not-nullable "
169 : "fields can be exposed' default='YES'/>"
170 : " <Option name='GML_ATTRIBUTES_TO_OGR_FIELDS' type='boolean' "
171 : "description='Whether GML attributes should be reported as OGR fields' "
172 : "default='NO'/>"
173 : " <Option name='INVERT_AXIS_ORDER_IF_LAT_LONG' type='boolean' "
174 : "description='Whether to present SRS and coordinate ordering in "
175 : "traditional GIS order' default='YES'/>"
176 : " <Option name='CONSIDER_EPSG_AS_URN' type='string-select' "
177 : "description='Whether to consider srsName like EPSG:XXXX as respecting "
178 : "EPSG axis order' default='AUTO'>"
179 : " <Value>AUTO</Value>"
180 : " <Value>YES</Value>"
181 : " <Value>NO</Value>"
182 : " </Option>"
183 : " <Option name='SWAP_COORDINATES' type='string-select' "
184 : "description='Whether the order of geometry coordinates should be "
185 : "inverted.' "
186 : "default='AUTO'>"
187 : " <Value>AUTO</Value>"
188 : " <Value>YES</Value>"
189 : " <Value>NO</Value>"
190 : " </Option>"
191 : " <Option name='READ_MODE' type='string-select' description='Read "
192 : "mode' default='AUTO'>"
193 : " <Value>AUTO</Value>"
194 : " <Value>STANDARD</Value>"
195 : " <Value>SEQUENTIAL_LAYERS</Value>"
196 : " <Value>INTERLEAVED_LAYERS</Value>"
197 : " </Option>"
198 : " <Option name='EXPOSE_GML_ID' type='string-select' "
199 : "description='Whether to make feature gml:id as a gml_id attribute' "
200 : "default='AUTO'>"
201 : " <Value>AUTO</Value>"
202 : " <Value>YES</Value>"
203 : " <Value>NO</Value>"
204 : " </Option>"
205 : " <Option name='EXPOSE_FID' type='string-select' description='Whether "
206 : "to make feature fid as a fid attribute' default='AUTO'>"
207 : " <Value>AUTO</Value>"
208 : " <Value>YES</Value>"
209 : " <Value>NO</Value>"
210 : " </Option>"
211 : " <Option name='DOWNLOAD_SCHEMA' type='boolean' description='Whether "
212 : "to download the remote application schema if needed (only for WFS "
213 : "currently)' default='YES'/>"
214 : " <Option name='REGISTRY' type='string' description='Filename of the "
215 : "registry with application schemas.'/>"
216 : " <Option name='USE_BBOX' type='boolean' description='Whether "
217 : "to use gml:boundedBy at feature level as feature geometry, "
218 : "if there are no other geometry' default='NO'/>"
219 1219 : "</OpenOptionList>");
220 :
221 1219 : poDriver->SetMetadataItem(
222 : GDAL_DMD_CREATIONOPTIONLIST,
223 : "<CreationOptionList>"
224 : " <Option name='XSISCHEMAURI' type='string' description='URI to be "
225 : "inserted as the schema location.'/>"
226 : " <Option name='XSISCHEMA' type='string-select' description='where to "
227 : "write a .xsd application schema. INTERNAL should not normally be "
228 : "used' default='EXTERNAL'>"
229 : " <Value>EXTERNAL</Value>"
230 : " <Value>INTERNAL</Value>"
231 : " <Value>OFF</Value>"
232 : " </Option>"
233 : " <Option name='PREFIX' type='string' description='Prefix for the "
234 : "application target namespace.' default='ogr'/>"
235 : " <Option name='STRIP_PREFIX' type='boolean' description='Whether to "
236 : "avoid writing the prefix of the application target namespace in the "
237 : "GML file.' default='NO'/>"
238 : " <Option name='TARGET_NAMESPACE' type='string' "
239 : "description='Application target namespace.' "
240 : "default='http://ogr.maptools.org/'/>"
241 : " <Option name='FORMAT' type='string-select' description='Version of "
242 : "GML to use' default='GML3.2'>"
243 : " <Value>GML2</Value>"
244 : " <Value>GML3</Value>"
245 : " <Value>GML3.2</Value>"
246 : " <Value>GML3Deegree</Value>"
247 : " </Option>"
248 : " <Option name='GML_FEATURE_COLLECTION' type='boolean' "
249 : "description='Whether to use the gml:FeatureCollection. Only valid for "
250 : "FORMAT=GML3/GML3.2' default='NO'/>"
251 : " <Option name='GML3_LONGSRS' type='boolean' description='Whether to "
252 : "write SRS with \"urn:ogc:def:crs:EPSG::\" prefix with GML3* versions' "
253 : "default='YES'/>"
254 : " <Option name='SRSNAME_FORMAT' type='string-select' "
255 : "description='Format of srsName (for GML3* versions)' "
256 : "default='OGC_URL'>"
257 : " <Value>SHORT</Value>"
258 : " <Value>OGC_URN</Value>"
259 : " <Value>OGC_URL</Value>"
260 : " </Option>"
261 : " <Option name='WRITE_FEATURE_BOUNDED_BY' type='boolean' "
262 : "description='Whether to write <gml:boundedBy> element for each "
263 : "feature with GML3* versions' default='YES'/>"
264 : " <Option name='SPACE_INDENTATION' type='boolean' "
265 : "description='Whether to indent the output for readability' "
266 : "default='YES'/>"
267 : " <Option name='SRSDIMENSION_LOC' type='string-select' "
268 : "description='(only valid for FORMAT=GML3xx) Location where to put "
269 : "srsDimension attribute' default='POSLIST'>"
270 : " <Value>POSLIST</Value>"
271 : " <Value>GEOMETRY</Value>"
272 : " <Value>GEOMETRY,POSLIST</Value>"
273 : " </Option>"
274 : " <Option name='GML_ID' type='string' description='Value of feature "
275 : "collection gml:id (GML 3.2 only)' default='aFeatureCollection'/>"
276 : " <Option name='NAME' type='string' description='Content of GML name "
277 : "element'/>"
278 : " <Option name='DESCRIPTION' type='string' description='Content of "
279 : "GML description element'/>"
280 1219 : "</CreationOptionList>");
281 :
282 1219 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST,
283 1219 : "<LayerCreationOptionList/>");
284 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
285 : "Integer Integer64 Real String Date DateTime "
286 1219 : "IntegerList Integer64List RealList StringList");
287 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES,
288 1219 : "Boolean Int16 Float32");
289 1219 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS,
290 1219 : "WidthPrecision Nullable Unique Comment");
291 :
292 1219 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_FIELDS, "YES");
293 1219 : poDriver->SetMetadataItem(GDAL_DCAP_UNIQUE_FIELDS, "YES");
294 1219 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES");
295 1219 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
296 1219 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES");
297 1219 : poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES");
298 :
299 1219 : poDriver->pfnOpen = OGRGMLDriverOpen;
300 1219 : poDriver->pfnIdentify = OGRGMLDriverIdentify;
301 1219 : poDriver->pfnCreate = OGRGMLDriverCreate;
302 :
303 1219 : GetGDALDriverManager()->RegisterDriver(poDriver);
304 : }
|