1 /******************************************************************************
2 * $Id: ogrgmldriver.cpp 29240 2015-05-24 10:58:38Z rouault $
3 *
4 * Project: OGR
5 * Purpose: OGRGMLDriver implementation
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.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 "ogr_gml.h"
31 #include "cpl_conv.h"
32 #include "cpl_multiproc.h"
33 #include "gmlreaderp.h"
34
35 CPL_CVSID("$Id: ogrgmldriver.cpp 29240 2015-05-24 10:58:38Z rouault $");
36
37 /************************************************************************/
38 /* OGRGMLDriverUnload() */
39 /************************************************************************/
40
OGRGMLDriverUnload(CPL_UNUSED GDALDriver * poDriver)41 static void OGRGMLDriverUnload(CPL_UNUSED GDALDriver* poDriver)
42 {
43 if( GMLReader::hMutex != NULL )
44 CPLDestroyMutex( GMLReader::hMutex );
45 GMLReader::hMutex = NULL;
46 }
47
48 /************************************************************************/
49 /* OGRGMLDriverIdentify() */
50 /************************************************************************/
51
OGRGMLDriverIdentify(GDALOpenInfo * poOpenInfo)52 static int OGRGMLDriverIdentify( GDALOpenInfo* poOpenInfo )
53
54 {
55 if( poOpenInfo->fpL == NULL )
56 {
57 if( strstr(poOpenInfo->pszFilename, "xsd=") != NULL )
58 return -1; /* must be later checked */
59 return FALSE;
60 }
61 /* Might be a OS-Mastermap gzipped GML, so let be nice and try to open */
62 /* it transparently with /vsigzip/ */
63 else
64 if ( poOpenInfo->pabyHeader[0] == 0x1f && poOpenInfo->pabyHeader[1] == 0x8b &&
65 EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "gz") &&
66 strncmp(poOpenInfo->pszFilename, "/vsigzip/", strlen("/vsigzip/")) != 0 )
67 {
68 return -1; /* must be later checked */
69 }
70 else
71 {
72 const char* szPtr = (const char*)poOpenInfo->pabyHeader;
73
74 if( ( (unsigned char)szPtr[0] == 0xEF )
75 && ( (unsigned char)szPtr[1] == 0xBB )
76 && ( (unsigned char)szPtr[2] == 0xBF) )
77 {
78 szPtr += 3;
79 }
80 /* -------------------------------------------------------------------- */
81 /* Here, we expect the opening chevrons of GML tree root element */
82 /* -------------------------------------------------------------------- */
83 if( szPtr[0] != '<' )
84 return FALSE;
85
86 if( !poOpenInfo->TryToIngest(4096) )
87 return FALSE;
88
89 return OGRGMLDataSource::CheckHeader((const char*)poOpenInfo->pabyHeader);
90 }
91 }
92
93 /************************************************************************/
94 /* Open() */
95 /************************************************************************/
96
OGRGMLDriverOpen(GDALOpenInfo * poOpenInfo)97 static GDALDataset *OGRGMLDriverOpen( GDALOpenInfo* poOpenInfo )
98
99 {
100 OGRGMLDataSource *poDS;
101
102 if( poOpenInfo->eAccess == GA_Update )
103 return NULL;
104
105 if( OGRGMLDriverIdentify( poOpenInfo ) == FALSE )
106 return NULL;
107
108 poDS = new OGRGMLDataSource();
109
110 if( !poDS->Open( poOpenInfo ) )
111 {
112 delete poDS;
113 return NULL;
114 }
115 else
116 return poDS;
117 }
118
119 /************************************************************************/
120 /* Create() */
121 /************************************************************************/
122
OGRGMLDriverCreate(const char * pszName,CPL_UNUSED int nBands,CPL_UNUSED int nXSize,CPL_UNUSED int nYSize,CPL_UNUSED GDALDataType eDT,char ** papszOptions)123 static GDALDataset *OGRGMLDriverCreate( const char * pszName,
124 CPL_UNUSED int nBands,
125 CPL_UNUSED int nXSize,
126 CPL_UNUSED int nYSize,
127 CPL_UNUSED GDALDataType eDT,
128 char **papszOptions )
129 {
130 OGRGMLDataSource *poDS = new OGRGMLDataSource();
131
132 if( !poDS->Create( pszName, papszOptions ) )
133 {
134 delete poDS;
135 return NULL;
136 }
137 else
138 return poDS;
139 }
140
141 /************************************************************************/
142 /* RegisterOGRGML() */
143 /************************************************************************/
144
RegisterOGRGML()145 void RegisterOGRGML()
146
147 {
148 GDALDriver *poDriver;
149
150 if( GDALGetDriverByName( "GML" ) == NULL )
151 {
152 poDriver = new GDALDriver();
153
154 poDriver->SetDescription( "GML" );
155 poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
156 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
157 "Geography Markup Language (GML)" );
158 poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gml" );
159 poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "gml xml" );
160 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
161 "drv_gml.html" );
162
163 poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
164 "<OpenOptionList>"
165 " <Option name='XSD' type='string' description='Name of the related application schema file (.xsd).'/>"
166 " <Option name='GFS_TEMPLATE' type='string' description='Filename of a .gfs template file to appli.'/>"
167 " <Option name='FORCE_SRS_DETECTION' type='boolean' description='Force a full scan to detect the SRS of layers.' default='NO'/>"
168 " <Option name='EMPTY_AS_NULL' type='boolean' description='Force empty fields to be reported as NULL. Set to NO so that not-nullable fields can be exposed' default='YES'/>"
169 " <Option name='GML_ATTRIBUTES_TO_OGR_FIELDS' type='boolean' description='Whether GML attributes should be reported as OGR fields' default='NO'/>"
170 " <Option name='INVERT_AXIS_ORDER_IF_LAT_LONG' type='boolean' description='Whether to present SRS and coordinate ordering in traditional GIS order' default='YES'/>"
171 " <Option name='CONSIDER_EPSG_AS_URN' type='string-select' description='Whether to consider srsName like EPSG:XXXX as respecting EPSG axis order' default='AUTO'>"
172 " <Value>AUTO</Value>"
173 " <Value>YES</Value>"
174 " <Value>NO</Value>"
175 " </Option>"
176 " <Option name='READ_MODE' type='string-select' description='Read mode' default='AUTO'>"
177 " <Value>AUTO</Value>"
178 " <Value>STANDARD</Value>"
179 " <Value>SEQUENTIAL_LAYERS</Value>"
180 " <Value>INTERLEAVED_LAYERS</Value>"
181 " </Option>"
182 " <Option name='EXPOSE_GML_ID' type='string-select' description='Whether to make feature gml:id as a gml_id attribute' default='AUTO'>"
183 " <Value>AUTO</Value>"
184 " <Value>YES</Value>"
185 " <Value>NO</Value>"
186 " </Option>"
187 " <Option name='EXPOSE_FID' type='string-select' description='Whether to make feature fid as a fid attribute' default='AUTO'>"
188 " <Value>AUTO</Value>"
189 " <Value>YES</Value>"
190 " <Value>NO</Value>"
191 " </Option>"
192 " <Option name='DOWNLOAD_SCHEMA' type='boolean' description='Whether to download the remote application schema if needed (only for WFS currently)' default='YES'/>"
193 " <Option name='REGISTRY' type='string' description='Filename of the registry with application schemas.'/>"
194 "</OpenOptionList>" );
195
196 poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
197 "<CreationOptionList>"
198 " <Option name='XSISCHEMAURI' type='string' description='URI to be inserted as the schema location.'/>"
199 " <Option name='XSISCHEMA' type='string-select' description='where to write a .xsd application schema. INTERNAL should not normally be used' default='EXTERNAL'>"
200 " <Value>EXTERNAL</Value>"
201 " <Value>INTERNAL</Value>"
202 " <Value>OFF</Value>"
203 " </Option>"
204 " <Option name='PREFIX' type='string' description='Prefix for the application target namespace.' default='ogr'/>"
205 " <Option name='STRIP_PREFIX' type='boolean' description='Whether to avoid writing the prefix of the application target namespace in the GML file.' default='NO'/>"
206 " <Option name='TARGET_NAMESPACE' type='string' description='Application target namespace.' default='http://ogr.maptools.org/'/>"
207 " <Option name='FORMAT' type='string-select' description='Version of GML to use' default='GML2'>"
208 " <Value>GML2</Value>"
209 " <Value>GML3</Value>"
210 " <Value>GML3.2</Value>"
211 " <Value>GML3Deegree</Value>"
212 " </Option>"
213 " <Option name='GML3_LONGSRS' type='boolean' description='Whether to write SRS with \"urn:ogc:def:crs:EPSG::\" prefix with GML3* versions' default='YES'/>"
214 " <Option name='WRITE_FEATURE_BOUNDED_BY' type='boolean' description='Whether to write <gml:boundedBy> element for each feature with GML3* versions' default='YES'/>"
215 " <Option name='SPACE_INDENTATION' type='boolean' description='Whether to indentate the output for readability' default='YES'/>"
216 " <Option name='SRSDIMENSION_LOC' type='string-select' description='(only valid for FORMAT=GML3xx) Location where to put srsDimension attribute' default='POSLIST'>"
217 " <Value>POSLIST</Value>"
218 " <Value>GEOMETRY</Value>"
219 " <Value>GEOMETRY,POSLIST</Value>"
220 " </Option>"
221 " <Option name='GML_ID' type='string' description='Value of feature collection gml:id (GML 3.2 only)' default='aFeatureCollection'/>"
222 " <Option name='NAME' type='string' description='Content of GML name element'/>"
223 " <Option name='DESCRIPTION' type='string' description='Content of GML description element'/>"
224 "</CreationOptionList>");
225
226 poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>");
227
228 poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime IntegerList Integer64List RealList StringList" );
229 poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
230 poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
231
232 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
233
234 poDriver->pfnOpen = OGRGMLDriverOpen;
235 poDriver->pfnIdentify = OGRGMLDriverIdentify;
236 poDriver->pfnCreate = OGRGMLDriverCreate;
237 poDriver->pfnUnloadDriver = OGRGMLDriverUnload;
238
239 GetGDALDriverManager()->RegisterDriver( poDriver );
240 }
241 }
242