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 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "ogr_gml.h" 14 : #include "cpl_conv.h" 15 : #include "cpl_multiproc.h" 16 : #include "gmlreaderp.h" 17 : 18 : /************************************************************************/ 19 : /* OGRGMLDriverIdentify() */ 20 : /************************************************************************/ 21 : 22 49716 : static int OGRGMLDriverIdentify(GDALOpenInfo *poOpenInfo) 23 : 24 : { 25 49716 : if (poOpenInfo->fpL == nullptr) 26 : { 27 44469 : if (strstr(poOpenInfo->pszFilename, "xsd=") != nullptr) 28 4 : return -1; /* must be later checked */ 29 44465 : return FALSE; 30 : } 31 : /* Might be a OS-Mastermap gzipped GML, so let be nice and try to open */ 32 : /* it transparently with /vsigzip/ */ 33 10516 : else if (poOpenInfo->pabyHeader[0] == 0x1f && 34 44 : poOpenInfo->pabyHeader[1] == 0x8b && 35 5291 : poOpenInfo->IsExtensionEqualToCI("gz") && 36 4 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsigzip/")) 37 : { 38 4 : return -1; /* must be later checked */ 39 : } 40 : else 41 : { 42 5243 : const char *szPtr = 43 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 44 : 45 5243 : if ((static_cast<unsigned char>(szPtr[0]) == 0xEF) && 46 9 : (static_cast<unsigned char>(szPtr[1]) == 0xBB) && 47 9 : (static_cast<unsigned char>(szPtr[2]) == 0xBF)) 48 : { 49 9 : szPtr += 3; 50 : } 51 : /* -------------------------------------------------------------------- 52 : */ 53 : /* Here, we expect the opening chevrons of GML tree root element */ 54 : /* -------------------------------------------------------------------- 55 : */ 56 5243 : if (szPtr[0] != '<') 57 4011 : return FALSE; 58 : 59 1232 : if (!poOpenInfo->TryToIngest(4096)) 60 0 : return FALSE; 61 : 62 1232 : if (poOpenInfo->IsSingleAllowedDriver("GML")) 63 128 : return TRUE; 64 : 65 2208 : return OGRGMLDataSource::CheckHeader( 66 1104 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader)); 67 : } 68 : } 69 : 70 : /************************************************************************/ 71 : /* Open() */ 72 : /************************************************************************/ 73 : 74 448 : static GDALDataset *OGRGMLDriverOpen(GDALOpenInfo *poOpenInfo) 75 : 76 : { 77 448 : if (poOpenInfo->eAccess == GA_Update) 78 0 : return nullptr; 79 : 80 448 : if (OGRGMLDriverIdentify(poOpenInfo) == FALSE) 81 15 : return nullptr; 82 : 83 433 : OGRGMLDataSource *poDS = new OGRGMLDataSource(); 84 : 85 433 : if (!poDS->Open(poOpenInfo)) 86 : { 87 13 : delete poDS; 88 13 : return nullptr; 89 : } 90 : else 91 420 : return poDS; 92 : } 93 : 94 : /************************************************************************/ 95 : /* Create() */ 96 : /************************************************************************/ 97 : 98 : static GDALDataset * 99 101 : OGRGMLDriverCreate(const char *pszName, CPL_UNUSED int nBands, 100 : CPL_UNUSED int nXSize, CPL_UNUSED int nYSize, 101 : CPL_UNUSED GDALDataType eDT, char **papszOptions) 102 : { 103 101 : OGRGMLDataSource *poDS = new OGRGMLDataSource(); 104 : 105 101 : if (!poDS->Create(pszName, papszOptions)) 106 : { 107 1 : delete poDS; 108 1 : return nullptr; 109 : } 110 : else 111 100 : return poDS; 112 : } 113 : 114 : /************************************************************************/ 115 : /* RegisterOGRGML() */ 116 : /************************************************************************/ 117 : 118 1686 : void RegisterOGRGML() 119 : 120 : { 121 1686 : if (GDALGetDriverByName("GML") != nullptr) 122 302 : return; 123 : 124 1384 : GDALDriver *poDriver = new GDALDriver(); 125 : 126 1384 : poDriver->SetDescription("GML"); 127 1384 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 128 1384 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 129 1384 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 130 1384 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES"); 131 1384 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 132 1384 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 133 1384 : "Geography Markup Language (GML)"); 134 1384 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gml"); 135 1384 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gml xml"); 136 1384 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/gml.html"); 137 1384 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 138 : 139 1384 : poDriver->SetMetadataItem( 140 : GDAL_DMD_OPENOPTIONLIST, 141 : "<OpenOptionList>" 142 : " <Option name='XSD' type='string' description='Name of the related " 143 : "application schema file (.xsd).'/>" 144 : " <Option name='GFS_TEMPLATE' type='string' description='Filename of " 145 : "a .gfs template file to apply.'/>" 146 : " <Option name='WRITE_GFS' type='string-select' description='Whether " 147 : "to write a .gfs file' default='AUTO'>" 148 : " <Value>AUTO</Value>" 149 : " <Value>YES</Value>" 150 : " <Value>NO</Value>" 151 : " </Option>" 152 : " <Option name='FORCE_SRS_DETECTION' type='boolean' " 153 : "description='Force a full scan to detect the SRS of layers.' " 154 : "default='NO'/>" 155 : " <Option name='EMPTY_AS_NULL' type='boolean' description='Force " 156 : "empty fields to be reported as NULL. Set to NO so that not-nullable " 157 : "fields can be exposed' default='YES'/>" 158 : " <Option name='GML_ATTRIBUTES_TO_OGR_FIELDS' type='boolean' " 159 : "description='Whether GML attributes should be reported as OGR fields' " 160 : "default='NO'/>" 161 : " <Option name='INVERT_AXIS_ORDER_IF_LAT_LONG' type='boolean' " 162 : "description='Whether to present SRS and coordinate ordering in " 163 : "traditional GIS order' default='YES'/>" 164 : " <Option name='CONSIDER_EPSG_AS_URN' type='string-select' " 165 : "description='Whether to consider srsName like EPSG:XXXX as respecting " 166 : "EPSG axis order' default='AUTO'>" 167 : " <Value>AUTO</Value>" 168 : " <Value>YES</Value>" 169 : " <Value>NO</Value>" 170 : " </Option>" 171 : " <Option name='SWAP_COORDINATES' type='string-select' " 172 : "description='Whether the order of geometry coordinates should be " 173 : "inverted.' " 174 : "default='AUTO'>" 175 : " <Value>AUTO</Value>" 176 : " <Value>YES</Value>" 177 : " <Value>NO</Value>" 178 : " </Option>" 179 : " <Option name='READ_MODE' type='string-select' description='Read " 180 : "mode' default='AUTO'>" 181 : " <Value>AUTO</Value>" 182 : " <Value>STANDARD</Value>" 183 : " <Value>SEQUENTIAL_LAYERS</Value>" 184 : " <Value>INTERLEAVED_LAYERS</Value>" 185 : " </Option>" 186 : " <Option name='EXPOSE_GML_ID' type='string-select' " 187 : "description='Whether to make feature gml:id as a gml_id attribute' " 188 : "default='AUTO'>" 189 : " <Value>AUTO</Value>" 190 : " <Value>YES</Value>" 191 : " <Value>NO</Value>" 192 : " </Option>" 193 : " <Option name='EXPOSE_FID' type='string-select' description='Whether " 194 : "to make feature fid as a fid attribute' default='AUTO'>" 195 : " <Value>AUTO</Value>" 196 : " <Value>YES</Value>" 197 : " <Value>NO</Value>" 198 : " </Option>" 199 : " <Option name='OGR_SCHEMA' type='string' description='" 200 : "Partially or totally overrides the auto-detected schema to use for " 201 : "creating the layer. " 202 : "The overrides are defined as a JSON list of field definitions. " 203 : "This can be a filename or a JSON string or a URL.'/>" 204 : " <Option name='DOWNLOAD_SCHEMA' type='boolean' description='Whether " 205 : "to download the remote application schema if needed (only for WFS " 206 : "currently)' default='YES'/>" 207 : " <Option name='REGISTRY' type='string' description='Filename of the " 208 : "registry with application schemas.'/>" 209 : " <Option name='USE_BBOX' type='boolean' description='Whether " 210 : "to use gml:boundedBy at feature level as feature geometry, " 211 : "if there are no other geometry' default='NO'/>" 212 : " <Option name='USE_SCHEMA_IMPORT' type='boolean' " 213 : "description='Whether " 214 : "to read schema for imports along with includes or not' default='NO'/>" 215 1384 : "</OpenOptionList>"); 216 : 217 1384 : poDriver->SetMetadataItem( 218 : GDAL_DMD_CREATIONOPTIONLIST, 219 : "<CreationOptionList>" 220 : " <Option name='XSISCHEMAURI' type='string' description='URI to be " 221 : "inserted as the schema location.'/>" 222 : " <Option name='XSISCHEMA' type='string-select' description='where to " 223 : "write a .xsd application schema. INTERNAL should not normally be " 224 : "used' default='EXTERNAL'>" 225 : " <Value>EXTERNAL</Value>" 226 : " <Value>INTERNAL</Value>" 227 : " <Value>OFF</Value>" 228 : " </Option>" 229 : " <Option name='PREFIX' type='string' description='Prefix for the " 230 : "application target namespace.' default='ogr'/>" 231 : " <Option name='STRIP_PREFIX' type='boolean' description='Whether to " 232 : "avoid writing the prefix of the application target namespace in the " 233 : "GML file.' default='NO'/>" 234 : " <Option name='TARGET_NAMESPACE' type='string' " 235 : "description='Application target namespace.' " 236 : "default='http://ogr.maptools.org/'/>" 237 : " <Option name='FORMAT' type='string-select' description='Version of " 238 : "GML to use' default='GML3.2'>" 239 : " <Value>GML2</Value>" 240 : " <Value>GML3</Value>" 241 : " <Value>GML3.2</Value>" 242 : " <Value>GML3Deegree</Value>" 243 : " </Option>" 244 : " <Option name='GML_FEATURE_COLLECTION' type='boolean' " 245 : "description='Whether to use the gml:FeatureCollection. Only valid for " 246 : "FORMAT=GML3/GML3.2' default='NO'/>" 247 : " <Option name='GML3_LONGSRS' type='boolean' description='Whether to " 248 : "write SRS with \"urn:ogc:def:crs:EPSG::\" prefix with GML3* versions' " 249 : "default='YES'/>" 250 : " <Option name='SRSNAME_FORMAT' type='string-select' " 251 : "description='Format of srsName (for GML3* versions)' " 252 : "default='OGC_URL'>" 253 : " <Value>SHORT</Value>" 254 : " <Value>OGC_URN</Value>" 255 : " <Value>OGC_URL</Value>" 256 : " </Option>" 257 : " <Option name='WRITE_FEATURE_BOUNDED_BY' type='boolean' " 258 : "description='Whether to write <gml:boundedBy> element for each " 259 : "feature with GML3* versions' default='YES'/>" 260 : " <Option name='SPACE_INDENTATION' type='boolean' " 261 : "description='Whether to indent the output for readability' " 262 : "default='YES'/>" 263 : " <Option name='SRSDIMENSION_LOC' type='string-select' " 264 : "description='(only valid for FORMAT=GML3xx) Location where to put " 265 : "srsDimension attribute' default='POSLIST'>" 266 : " <Value>POSLIST</Value>" 267 : " <Value>GEOMETRY</Value>" 268 : " <Value>GEOMETRY,POSLIST</Value>" 269 : " </Option>" 270 : " <Option name='GML_ID' type='string' description='Value of feature " 271 : "collection gml:id (GML 3.2 only)' default='aFeatureCollection'/>" 272 : " <Option name='NAME' type='string' description='Content of GML name " 273 : "element'/>" 274 : " <Option name='DESCRIPTION' type='string' description='Content of " 275 : "GML description element'/>" 276 1384 : "</CreationOptionList>"); 277 : 278 1384 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, 279 1384 : "<LayerCreationOptionList/>"); 280 1384 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, 281 : "Integer Integer64 Real String Date DateTime " 282 1384 : "IntegerList Integer64List RealList StringList"); 283 1384 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 284 1384 : "Boolean Int16 Float32"); 285 1384 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 286 1384 : "WidthPrecision Nullable Unique Comment"); 287 : 288 1384 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_FIELDS, "YES"); 289 1384 : poDriver->SetMetadataItem(GDAL_DCAP_UNIQUE_FIELDS, "YES"); 290 1384 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES"); 291 1384 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 292 1384 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 293 1384 : poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES"); 294 : 295 1384 : poDriver->pfnOpen = OGRGMLDriverOpen; 296 1384 : poDriver->pfnIdentify = OGRGMLDriverIdentify; 297 1384 : poDriver->pfnCreate = OGRGMLDriverCreate; 298 : 299 1384 : GetGDALDriverManager()->RegisterDriver(poDriver); 300 : }