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 48776 : static int OGRGMLDriverIdentify(GDALOpenInfo *poOpenInfo) 23 : 24 : { 25 48776 : if (poOpenInfo->fpL == nullptr) 26 : { 27 43738 : if (strstr(poOpenInfo->pszFilename, "xsd=") != nullptr) 28 4 : return -1; /* must be later checked */ 29 43734 : 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 10098 : else if (poOpenInfo->pabyHeader[0] == 0x1f && 34 22 : poOpenInfo->pabyHeader[1] == 0x8b && 35 5064 : EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "gz") && 36 4 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsigzip/")) 37 : { 38 4 : return -1; /* must be later checked */ 39 : } 40 : else 41 : { 42 5034 : const char *szPtr = 43 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader); 44 : 45 5034 : 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 5034 : if (szPtr[0] != '<') 57 3871 : return FALSE; 58 : 59 1163 : if (!poOpenInfo->TryToIngest(4096)) 60 0 : return FALSE; 61 : 62 1163 : if (poOpenInfo->IsSingleAllowedDriver("GML")) 63 68 : return TRUE; 64 : 65 2190 : return OGRGMLDataSource::CheckHeader( 66 1095 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader)); 67 : } 68 : } 69 : 70 : /************************************************************************/ 71 : /* Open() */ 72 : /************************************************************************/ 73 : 74 414 : static GDALDataset *OGRGMLDriverOpen(GDALOpenInfo *poOpenInfo) 75 : 76 : { 77 414 : if (poOpenInfo->eAccess == GA_Update) 78 0 : return nullptr; 79 : 80 414 : if (OGRGMLDriverIdentify(poOpenInfo) == FALSE) 81 15 : return nullptr; 82 : 83 399 : OGRGMLDataSource *poDS = new OGRGMLDataSource(); 84 : 85 399 : if (!poDS->Open(poOpenInfo)) 86 : { 87 3 : delete poDS; 88 3 : return nullptr; 89 : } 90 : else 91 396 : return poDS; 92 : } 93 : 94 : /************************************************************************/ 95 : /* Create() */ 96 : /************************************************************************/ 97 : 98 : static GDALDataset * 99 99 : 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 99 : OGRGMLDataSource *poDS = new OGRGMLDataSource(); 104 : 105 99 : if (!poDS->Create(pszName, papszOptions)) 106 : { 107 1 : delete poDS; 108 1 : return nullptr; 109 : } 110 : else 111 98 : return poDS; 112 : } 113 : 114 : /************************************************************************/ 115 : /* RegisterOGRGML() */ 116 : /************************************************************************/ 117 : 118 1595 : void RegisterOGRGML() 119 : 120 : { 121 1595 : if (GDALGetDriverByName("GML") != nullptr) 122 302 : return; 123 : 124 1293 : GDALDriver *poDriver = new GDALDriver(); 125 : 126 1293 : poDriver->SetDescription("GML"); 127 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 128 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 129 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 130 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES"); 131 1293 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 132 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 133 1293 : "Geography Markup Language (GML)"); 134 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gml"); 135 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gml xml"); 136 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/gml.html"); 137 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); 138 : 139 1293 : 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='DOWNLOAD_SCHEMA' type='boolean' description='Whether " 200 : "to download the remote application schema if needed (only for WFS " 201 : "currently)' default='YES'/>" 202 : " <Option name='REGISTRY' type='string' description='Filename of the " 203 : "registry with application schemas.'/>" 204 : " <Option name='USE_BBOX' type='boolean' description='Whether " 205 : "to use gml:boundedBy at feature level as feature geometry, " 206 : "if there are no other geometry' default='NO'/>" 207 : " <Option name='USE_SCHEMA_IMPORT' type='boolean' " 208 : "description='Whether " 209 : "to read schema for imports along with includes or not' default='NO'/>" 210 1293 : "</OpenOptionList>"); 211 : 212 1293 : poDriver->SetMetadataItem( 213 : GDAL_DMD_CREATIONOPTIONLIST, 214 : "<CreationOptionList>" 215 : " <Option name='XSISCHEMAURI' type='string' description='URI to be " 216 : "inserted as the schema location.'/>" 217 : " <Option name='XSISCHEMA' type='string-select' description='where to " 218 : "write a .xsd application schema. INTERNAL should not normally be " 219 : "used' default='EXTERNAL'>" 220 : " <Value>EXTERNAL</Value>" 221 : " <Value>INTERNAL</Value>" 222 : " <Value>OFF</Value>" 223 : " </Option>" 224 : " <Option name='PREFIX' type='string' description='Prefix for the " 225 : "application target namespace.' default='ogr'/>" 226 : " <Option name='STRIP_PREFIX' type='boolean' description='Whether to " 227 : "avoid writing the prefix of the application target namespace in the " 228 : "GML file.' default='NO'/>" 229 : " <Option name='TARGET_NAMESPACE' type='string' " 230 : "description='Application target namespace.' " 231 : "default='http://ogr.maptools.org/'/>" 232 : " <Option name='FORMAT' type='string-select' description='Version of " 233 : "GML to use' default='GML3.2'>" 234 : " <Value>GML2</Value>" 235 : " <Value>GML3</Value>" 236 : " <Value>GML3.2</Value>" 237 : " <Value>GML3Deegree</Value>" 238 : " </Option>" 239 : " <Option name='GML_FEATURE_COLLECTION' type='boolean' " 240 : "description='Whether to use the gml:FeatureCollection. Only valid for " 241 : "FORMAT=GML3/GML3.2' default='NO'/>" 242 : " <Option name='GML3_LONGSRS' type='boolean' description='Whether to " 243 : "write SRS with \"urn:ogc:def:crs:EPSG::\" prefix with GML3* versions' " 244 : "default='YES'/>" 245 : " <Option name='SRSNAME_FORMAT' type='string-select' " 246 : "description='Format of srsName (for GML3* versions)' " 247 : "default='OGC_URL'>" 248 : " <Value>SHORT</Value>" 249 : " <Value>OGC_URN</Value>" 250 : " <Value>OGC_URL</Value>" 251 : " </Option>" 252 : " <Option name='WRITE_FEATURE_BOUNDED_BY' type='boolean' " 253 : "description='Whether to write <gml:boundedBy> element for each " 254 : "feature with GML3* versions' default='YES'/>" 255 : " <Option name='SPACE_INDENTATION' type='boolean' " 256 : "description='Whether to indent the output for readability' " 257 : "default='YES'/>" 258 : " <Option name='SRSDIMENSION_LOC' type='string-select' " 259 : "description='(only valid for FORMAT=GML3xx) Location where to put " 260 : "srsDimension attribute' default='POSLIST'>" 261 : " <Value>POSLIST</Value>" 262 : " <Value>GEOMETRY</Value>" 263 : " <Value>GEOMETRY,POSLIST</Value>" 264 : " </Option>" 265 : " <Option name='GML_ID' type='string' description='Value of feature " 266 : "collection gml:id (GML 3.2 only)' default='aFeatureCollection'/>" 267 : " <Option name='NAME' type='string' description='Content of GML name " 268 : "element'/>" 269 : " <Option name='DESCRIPTION' type='string' description='Content of " 270 : "GML description element'/>" 271 1293 : "</CreationOptionList>"); 272 : 273 1293 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, 274 1293 : "<LayerCreationOptionList/>"); 275 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, 276 : "Integer Integer64 Real String Date DateTime " 277 1293 : "IntegerList Integer64List RealList StringList"); 278 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 279 1293 : "Boolean Int16 Float32"); 280 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 281 1293 : "WidthPrecision Nullable Unique Comment"); 282 : 283 1293 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_FIELDS, "YES"); 284 1293 : poDriver->SetMetadataItem(GDAL_DCAP_UNIQUE_FIELDS, "YES"); 285 1293 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES"); 286 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 287 1293 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 288 1293 : poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES"); 289 : 290 1293 : poDriver->pfnOpen = OGRGMLDriverOpen; 291 1293 : poDriver->pfnIdentify = OGRGMLDriverIdentify; 292 1293 : poDriver->pfnCreate = OGRGMLDriverCreate; 293 : 294 1293 : GetGDALDriverManager()->RegisterDriver(poDriver); 295 : }