Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: FileGDB Translator 4 : * Purpose: Implements FileGDB OGR driver. 5 : * Author: Even Rouault, <even.rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2010, Ragi Yaser Burhum 9 : * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca> 10 : * Copyright (c) 2011-2023, Even Rouault <even dot rouault at spatialys.com> 11 : * 12 : * SPDX-License-Identifier: MIT 13 : ****************************************************************************/ 14 : 15 : #include "ogrsf_frmts.h" 16 : #include "FGdbDriverCore.h" 17 : 18 : #define ENDS_WITH(str, strLen, end) \ 19 : (strLen >= strlen(end) && EQUAL(str + strLen - strlen(end), end)) 20 : 21 : /************************************************************************/ 22 : /* OGRFileGDBDriverIdentifyInternal() */ 23 : /************************************************************************/ 24 : 25 43320 : GDALIdentifyEnum OGRFileGDBDriverIdentifyInternal(GDALOpenInfo *poOpenInfo, 26 : const char *&pszFilename) 27 : { 28 : // First check if we have to do any work. 29 43320 : size_t nLen = strlen(pszFilename); 30 43320 : if (ENDS_WITH(pszFilename, nLen, ".gdb") || 31 42244 : ENDS_WITH(pszFilename, nLen, ".gdb/")) 32 : { 33 : // Check that the filename is really a directory, to avoid confusion 34 : // with Garmin MapSource - gdb format which can be a problem when the 35 : // driver is loaded as a plugin, and loaded before the GPSBabel driver 36 : // (http://trac.osgeo.org/osgeo4w/ticket/245) 37 242 : if (STARTS_WITH(pszFilename, "/vsi") || !poOpenInfo->bStatOK || 38 109 : !poOpenInfo->bIsDirectory) 39 : { 40 136 : return GDAL_IDENTIFY_FALSE; 41 : } 42 106 : return GDAL_IDENTIFY_TRUE; 43 : } 44 43078 : else if (EQUAL(pszFilename, ".")) 45 : { 46 3 : GDALIdentifyEnum eRet = GDAL_IDENTIFY_FALSE; 47 3 : char *pszCurrentDir = CPLGetCurrentDir(); 48 3 : if (pszCurrentDir) 49 : { 50 3 : const char *pszTmp = pszCurrentDir; 51 3 : eRet = OGRFileGDBDriverIdentifyInternal(poOpenInfo, pszTmp); 52 3 : CPLFree(pszCurrentDir); 53 : } 54 3 : return eRet; 55 : } 56 : else 57 : { 58 43075 : return GDAL_IDENTIFY_FALSE; 59 : } 60 : } 61 : 62 : /************************************************************************/ 63 : /* OGRFileGDBDriverIdentify() */ 64 : /************************************************************************/ 65 : 66 43264 : static int OGRFileGDBDriverIdentify(GDALOpenInfo *poOpenInfo) 67 : { 68 43264 : const char *pszFilename = poOpenInfo->pszFilename; 69 86528 : return OGRFileGDBDriverIdentifyInternal(poOpenInfo, pszFilename); 70 : } 71 : 72 : /************************************************************************/ 73 : /* OGRFileGDBDriverSetCommonMetadata() */ 74 : /************************************************************************/ 75 : 76 1308 : void OGRFileGDBDriverSetCommonMetadata(GDALDriver *poDriver) 77 : { 78 1308 : poDriver->SetDescription(DRIVER_NAME); 79 1308 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ESRI FileGDB"); 80 1308 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); 81 1308 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_LAYER, "YES"); 82 1308 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); 83 1308 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); 84 1308 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES"); 85 1308 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gdb"); 86 1308 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 87 1308 : "drivers/vector/filegdb.html"); 88 : 89 1308 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST, 90 1308 : "<CreationOptionList/>"); 91 : 92 1308 : poDriver->SetMetadataItem( 93 : GDAL_DS_LAYER_CREATIONOPTIONLIST, 94 : "<LayerCreationOptionList>" 95 : " <Option name='FEATURE_DATASET' type='string' " 96 : "description='FeatureDataset folder into to put the new layer'/>" 97 : " <Option name='LAYER_ALIAS' type='string' description='Alias of " 98 : "layer name'/>" 99 : " <Option name='GEOMETRY_NAME' type='string' description='Name of " 100 : "geometry column' default='SHAPE'/>" 101 : " <Option name='GEOMETRY_NULLABLE' type='boolean' " 102 : "description='Whether the values of the geometry column can be NULL' " 103 : "default='YES'/>" 104 : " <Option name='FID' type='string' description='Name of OID column' " 105 : "default='OBJECTID' deprecated_alias='OID_NAME'/>" 106 : " <Option name='XYTOLERANCE' type='float' description='Snapping " 107 : "tolerance, used for advanced ArcGIS features like network and " 108 : "topology rules, on 2D coordinates, in the units of the CRS'/>" 109 : " <Option name='ZTOLERANCE' type='float' description='Snapping " 110 : "tolerance, used for advanced ArcGIS features like network and " 111 : "topology rules, on Z coordinates, in the units of the CRS'/>" 112 : " <Option name='MTOLERANCE' type='float' description='Snapping " 113 : "tolerance, used for advanced ArcGIS features like network and " 114 : "topology rules, on M coordinates'/>" 115 : " <Option name='XORIGIN' type='float' description='X origin of the " 116 : "coordinate precision grid'/>" 117 : " <Option name='YORIGIN' type='float' description='Y origin of the " 118 : "coordinate precision grid'/>" 119 : " <Option name='ZORIGIN' type='float' description='Z origin of the " 120 : "coordinate precision grid'/>" 121 : " <Option name='MORIGIN' type='float' description='M origin of the " 122 : "coordinate precision grid'/>" 123 : " <Option name='XYSCALE' type='float' description='X,Y scale of the " 124 : "coordinate precision grid'/>" 125 : " <Option name='ZSCALE' type='float' description='Z scale of the " 126 : "coordinate precision grid'/>" 127 : " <Option name='MSCALE' type='float' description='M scale of the " 128 : "coordinate precision grid'/>" 129 : " <Option name='XML_DEFINITION' type='string' description='XML " 130 : "definition to create the new table. The root node of such a XML " 131 : "definition must be a <esri:DataElement> element conformant to " 132 : "FileGDBAPI.xsd'/>" 133 : " <Option name='CREATE_MULTIPATCH' type='boolean' " 134 : "description='Whether to write geometries of layers of type " 135 : "MultiPolygon as MultiPatch' default='NO'/>" 136 : " <Option name='COLUMN_TYPES' type='string' description='A list of " 137 : "strings of format field_name=fgdb_field_type (separated by comma) to " 138 : "force the FileGDB column type of fields to be created'/>" 139 : " <Option name='CONFIGURATION_KEYWORD' type='string-select' " 140 : "description='Customize how data is stored. By default text in UTF-8 " 141 : "and data up to 1TB'>" 142 : " <Value>DEFAULTS</Value>" 143 : " <Value>TEXT_UTF16</Value>" 144 : " <Value>MAX_FILE_SIZE_4GB</Value>" 145 : " <Value>MAX_FILE_SIZE_256TB</Value>" 146 : " <Value>GEOMETRY_OUTOFLINE</Value>" 147 : " <Value>BLOB_OUTOFLINE</Value>" 148 : " <Value>GEOMETRY_AND_BLOB_OUTOFLINE</Value>" 149 : " </Option>" 150 : " <Option name='CREATE_SHAPE_AREA_AND_LENGTH_FIELDS' type='boolean' " 151 : "description='Whether to create special Shape_Length and Shape_Area " 152 : "fields' default='NO'/>" 153 1308 : "</LayerCreationOptionList>"); 154 : 155 : // Setting to another value than the default one doesn't really work 156 : // with the SDK 157 : // Option name='AREA_FIELD_NAME' type='string' description='Name of 158 : // the column that contains the geometry area' default='Shape_Area' 159 : // Option name='length_field_name' type='string' description='Name of 160 : // the column that contains the geometry length' 161 : // default='Shape_Length' 162 : 163 1308 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, 164 1308 : "Integer Real String Date DateTime Binary"); 165 1308 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, 166 1308 : "Int16 Float32"); 167 1308 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, 168 : "Nullable Default " 169 1308 : "AlternativeName Domain"); 170 1308 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_FIELDS, "YES"); 171 1308 : poDriver->SetMetadataItem(GDAL_DCAP_DEFAULT_FIELDS, "YES"); 172 1308 : poDriver->SetMetadataItem(GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES"); 173 1308 : poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); 174 1308 : poDriver->SetMetadataItem(GDAL_DCAP_FIELD_DOMAINS, "YES"); 175 1308 : poDriver->SetMetadataItem(GDAL_DCAP_RELATIONSHIPS, "YES"); 176 1308 : poDriver->SetMetadataItem(GDAL_DCAP_RENAME_LAYERS, "YES"); 177 1308 : poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); 178 1308 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); 179 1308 : poDriver->SetMetadataItem(GDAL_DMD_GEOMETRY_FLAGS, 180 : "EquatesMultiAndSingleLineStringDuringWrite " 181 1308 : "EquatesMultiAndSinglePolygonDuringWrite"); 182 : // see https://support.esri.com/en/technical-article/000010906 183 1308 : poDriver->SetMetadataItem( 184 : GDAL_DMD_ILLEGAL_FIELD_NAMES, 185 : "ADD ALTER AND BETWEEN BY COLUMN CREATE DELETE DROP EXISTS FOR FROM " 186 : "GROUP IN INSERT INTO IS LIKE NOT NULL OR ORDER SELECT SET TABLE " 187 1308 : "UPDATE VALUES WHERE"); 188 1308 : poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DOMAIN_TYPES, 189 1308 : "Coded Range"); 190 1308 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, 191 1308 : "NATIVE OGRSQL SQLITE"); 192 1308 : poDriver->SetMetadataItem(GDAL_DMD_RELATIONSHIP_RELATED_TABLE_TYPES, 193 1308 : "features media"); 194 1308 : poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES"); 195 : 196 1308 : poDriver->pfnIdentify = OGRFileGDBDriverIdentify; 197 1308 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); 198 1308 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); 199 1308 : } 200 : 201 : /************************************************************************/ 202 : /* DeclareDeferredOGRFileGDBPlugin() */ 203 : /************************************************************************/ 204 : 205 : #ifdef PLUGIN_FILENAME 206 1595 : void DeclareDeferredOGRFileGDBPlugin() 207 : { 208 1595 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr) 209 : { 210 302 : return; 211 : } 212 1293 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); 213 : #ifdef PLUGIN_INSTALLATION_MESSAGE 214 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, 215 : PLUGIN_INSTALLATION_MESSAGE); 216 : #endif 217 1293 : OGRFileGDBDriverSetCommonMetadata(poDriver); 218 1293 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); 219 : } 220 : #endif