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