LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/filegdb - FGdbLayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 970 725 74.7 %
Date: 2012-12-26 Functions: 45 36 80.0 %

       1                 : /******************************************************************************
       2                 : * $Id: FGdbLayer.cpp 25208 2012-11-05 18:34:41Z rouault $
       3                 : *
       4                 : * Project:  OpenGIS Simple Features Reference Implementation
       5                 : * Purpose:  Implements FileGDB OGR layer.
       6                 : * Author:   Ragi Yaser Burhum, ragi@burhum.com
       7                 : *           Paul Ramsey, pramsey at cleverelephant.ca
       8                 : *
       9                 : ******************************************************************************
      10                 : * Copyright (c) 2010, Ragi Yaser Burhum
      11                 : * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
      12                 : *
      13                 : * Permission is hereby granted, free of charge, to any person obtaining a
      14                 : * copy of this software and associated documentation files (the "Software"),
      15                 : * to deal in the Software without restriction, including without limitation
      16                 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 : * and/or sell copies of the Software, and to permit persons to whom the
      18                 : * Software is furnished to do so, subject to the following conditions:
      19                 : *
      20                 : * The above copyright notice and this permission notice shall be included
      21                 : * in all copies or substantial portions of the Software.
      22                 : *
      23                 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 : * DEALINGS IN THE SOFTWARE.
      30                 : ****************************************************************************/
      31                 : 
      32                 : #include "ogr_fgdb.h"
      33                 : #include "ogrpgeogeometry.h"
      34                 : #include "cpl_conv.h"
      35                 : #include "cpl_string.h"
      36                 : #include "FGdbUtils.h"
      37                 : #include "cpl_minixml.h" // the only way right now to extract schema information
      38                 : 
      39                 : CPL_CVSID("$Id: FGdbLayer.cpp 25208 2012-11-05 18:34:41Z rouault $");
      40                 : 
      41                 : using std::string;
      42                 : using std::wstring;
      43                 : 
      44                 : /************************************************************************/
      45                 : /*                           FGdbBaseLayer()                            */
      46                 : /************************************************************************/
      47             186 : FGdbBaseLayer::FGdbBaseLayer() :
      48                 :     m_pFeatureDefn(NULL), m_pSRS(NULL), m_pEnumRows(NULL),
      49             186 :     m_supressColumnMappingError(false), m_forceMulti(false)
      50                 : {
      51             186 : }
      52                 : 
      53                 : /************************************************************************/
      54                 : /*                          ~FGdbBaseLayer()                            */
      55                 : /************************************************************************/
      56             186 : FGdbBaseLayer::~FGdbBaseLayer()
      57                 : {
      58             186 :     if (m_pFeatureDefn)
      59                 :     {
      60             183 :         m_pFeatureDefn->Release();
      61             183 :         m_pFeatureDefn = NULL;
      62                 :     }
      63                 : 
      64             186 :     if (m_pEnumRows)
      65                 :     {
      66             186 :         delete m_pEnumRows;
      67             186 :         m_pEnumRows = NULL;
      68                 :     }
      69                 : 
      70             186 :     if (m_pSRS)
      71                 :     {
      72             166 :         m_pSRS->Release();
      73             166 :         m_pSRS = NULL;
      74                 :     }
      75             186 : }
      76                 : 
      77                 : /************************************************************************/
      78                 : /*                           GetNextFeature()                           */
      79                 : /************************************************************************/
      80                 : 
      81            1062 : OGRFeature* FGdbBaseLayer::GetNextFeature()
      82                 : {
      83               0 :     while (1) //want to skip errors
      84                 :     {
      85            1062 :         if (m_pEnumRows == NULL)
      86               0 :             return NULL;
      87                 : 
      88                 :         long hr;
      89                 : 
      90            1062 :         Row row;
      91                 : 
      92            1062 :         if (FAILED(hr = m_pEnumRows->Next(row)))
      93                 :         {
      94               0 :             GDBErr(hr, "Failed fetching features");
      95               0 :             return NULL;
      96                 :         }
      97                 : 
      98            1062 :         if (hr != S_OK)
      99                 :         {
     100                 :         // It's OK, we are done fetching - failure is catched by FAILED macro
     101             167 :             return NULL;
     102                 :         }
     103                 : 
     104             895 :         OGRFeature* pOGRFeature = NULL;
     105                 : 
     106             895 :         if (!OGRFeatureFromGdbRow(&row,  &pOGRFeature))
     107                 :         {
     108               0 :             int32 oid = -1;
     109               0 :             row.GetOID(oid);
     110                 : 
     111               0 :             GDBErr(hr, CPLSPrintf("Failed translating FGDB row [%d] to OGR Feature", oid));
     112                 : 
     113                 :             //return NULL;
     114               0 :             continue; //skip feature
     115                 :         }
     116                 : 
     117             895 :         return pOGRFeature;
     118                 :     }
     119                 : }
     120                 : 
     121                 : /************************************************************************/
     122                 : /*                              FGdbLayer()                             */
     123                 : /************************************************************************/
     124             185 : FGdbLayer::FGdbLayer():
     125                 :     m_pDS(NULL), m_pTable(NULL), m_wstrSubfields(L"*"), m_pOGRFilterGeometry(NULL), 
     126                 :     m_bFilterDirty(true), 
     127             185 :     m_bLaunderReservedKeywords(true)
     128                 : {
     129             185 :     m_bBulkLoadAllowed = -1; /* uninitialized */
     130             185 :     m_bBulkLoadInProgress = FALSE;
     131             185 :     m_pEnumRows = new EnumRows;
     132                 : 
     133                 : #ifdef EXTENT_WORKAROUND
     134             185 :     m_bLayerEnvelopeValid = false;
     135             185 :     m_bLayerJustCreated = false;
     136                 : #endif
     137             185 : }
     138                 : 
     139                 : /************************************************************************/
     140                 : /*                            ~FGdbLayer()                              */
     141                 : /************************************************************************/
     142                 : 
     143             185 : FGdbLayer::~FGdbLayer()
     144                 : {
     145             185 :     EndBulkLoad();
     146                 : 
     147                 : #ifdef EXTENT_WORKAROUND
     148             185 :     WorkAroundExtentProblem();
     149                 : #endif
     150                 : 
     151                 :     // NOTE: never delete m_pDS - the memory doesn't belong to us
     152                 :     // TODO: check if we need to close the table or if the destructor 
     153                 :     // takes care of closing as it should
     154             185 :     if (m_pTable)
     155                 :     {
     156             182 :         delete m_pTable;
     157             182 :         m_pTable = NULL;
     158                 :     }
     159                 : 
     160             185 :     if (m_pOGRFilterGeometry)
     161                 :     {
     162               0 :         OGRGeometryFactory::destroyGeometry(m_pOGRFilterGeometry);
     163               0 :         m_pOGRFilterGeometry = NULL;
     164                 :     }
     165                 :     
     166             185 : }
     167                 : 
     168                 : #ifdef EXTENT_WORKAROUND
     169                 : 
     170                 : /************************************************************************/
     171                 : /*                     UpdateRowWithGeometry()                          */
     172                 : /************************************************************************/
     173                 : 
     174               0 : bool FGdbLayer::UpdateRowWithGeometry(Row& row, OGRGeometry* poGeom)
     175                 : {
     176               0 :     ShapeBuffer shape;
     177                 :     long hr;
     178                 : 
     179                 :     /* Write geometry to a buffer */
     180               0 :     GByte *pabyShape = NULL;
     181               0 :     int nShapeSize = 0;
     182               0 :     if ( OGRWriteToShapeBin( poGeom, &pabyShape, &nShapeSize ) != OGRERR_NONE )
     183               0 :         return false;
     184                 : 
     185                 :     /* Copy it into a ShapeBuffer */
     186               0 :     if ( nShapeSize > 0 )
     187                 :     {
     188               0 :         shape.Allocate(nShapeSize);
     189               0 :         memcpy(shape.shapeBuffer, pabyShape, nShapeSize);
     190               0 :         shape.inUseLength = nShapeSize;
     191                 :     }
     192                 : 
     193                 :     /* Free the shape buffer */
     194               0 :     CPLFree(pabyShape);
     195                 : 
     196                 :     /* Write ShapeBuffer into the Row */
     197               0 :     hr = row.SetGeometry(shape);
     198               0 :     if (FAILED(hr))
     199                 :     {
     200               0 :         return false;
     201                 :     }
     202                 : 
     203                 :     /* Update row */
     204               0 :     hr = m_pTable->Update(row);
     205               0 :     if (FAILED(hr))
     206                 :     {
     207               0 :         return false;
     208                 :     }
     209                 : 
     210               0 :     return true;
     211                 : }
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                    WorkAroundExtentProblem()                         */
     215                 : /*                                                                      */
     216                 : /* Work-around problem with FileGDB API 1.1 on Linux 64bit. See #4455   */
     217                 : /************************************************************************/
     218                 : 
     219             185 : void FGdbLayer::WorkAroundExtentProblem()
     220                 : {
     221             185 :     if (!m_bLayerJustCreated || !m_bLayerEnvelopeValid)
     222             171 :         return;
     223                 : 
     224              14 :     OGREnvelope sEnvelope;
     225              14 :     if (GetExtent(&sEnvelope, TRUE) != OGRERR_NONE)
     226               0 :         return;
     227                 : 
     228                 :     /* The characteristic of the bug is that the reported extent */
     229                 :     /* is the real extent truncated incorrectly to integer values */
     230                 :     /* We work around that by temporary updating one feature with a geometry */
     231                 :     /* whose coordinates are integer values but ceil'ed and floor'ed */
     232                 :     /* such that they include the real layer extent. */
     233              14 :     if (((double)(int)sEnvelope.MinX == sEnvelope.MinX &&
     234                 :          (double)(int)sEnvelope.MinY == sEnvelope.MinY &&
     235                 :          (double)(int)sEnvelope.MaxX == sEnvelope.MaxX &&
     236                 :          (double)(int)sEnvelope.MaxY == sEnvelope.MaxY) &&
     237                 :         (fabs(sEnvelope.MinX - sLayerEnvelope.MinX) > 1e-5 ||
     238                 :          fabs(sEnvelope.MinY - sLayerEnvelope.MinY) > 1e-5 ||
     239                 :          fabs(sEnvelope.MaxX - sLayerEnvelope.MaxX) > 1e-5 ||
     240                 :          fabs(sEnvelope.MaxY - sLayerEnvelope.MaxY) > 1e-5))
     241                 :     {
     242                 :         long           hr;
     243               0 :         Row            row;
     244               0 :         EnumRows       enumRows;
     245                 : 
     246               0 :         if (FAILED(hr = m_pTable->Search(StringToWString("*"), StringToWString(""), true, enumRows)))
     247                 :             return;
     248                 : 
     249               0 :         if (FAILED(hr = enumRows.Next(row)))
     250                 :             return;
     251                 : 
     252               0 :         if (hr != S_OK)
     253                 :             return;
     254                 : 
     255                 :         /* Backup original shape buffer */
     256               0 :         ShapeBuffer originalGdbGeometry;
     257               0 :         if (FAILED(hr = row.GetGeometry(originalGdbGeometry)))
     258                 :             return;
     259                 : 
     260               0 :         OGRGeometry* pOGRGeo = NULL;
     261               0 :         if ((!GDBGeometryToOGRGeometry(m_forceMulti, &originalGdbGeometry, m_pSRS, &pOGRGeo)) || pOGRGeo == NULL)
     262                 :         {
     263               0 :             delete pOGRGeo;
     264                 :             return;
     265                 :         }
     266                 : 
     267               0 :         OGRwkbGeometryType eType = wkbFlatten(pOGRGeo->getGeometryType());
     268                 : 
     269               0 :         delete pOGRGeo;
     270               0 :         pOGRGeo = NULL;
     271                 : 
     272               0 :         OGRPoint oP1(floor(sLayerEnvelope.MinX), floor(sLayerEnvelope.MinY));
     273               0 :         OGRPoint oP2(ceil(sLayerEnvelope.MaxX), ceil(sLayerEnvelope.MaxY));
     274                 : 
     275               0 :         OGRLinearRing oLR;
     276               0 :         oLR.addPoint(&oP1);
     277               0 :         oLR.addPoint(&oP2);
     278               0 :         oLR.addPoint(&oP1);
     279                 : 
     280               0 :         if ( eType == wkbPoint )
     281                 :         {
     282               0 :             UpdateRowWithGeometry(row, &oP1);
     283               0 :             UpdateRowWithGeometry(row, &oP2);
     284                 :         }
     285               0 :         else if ( eType == wkbLineString )
     286                 :         {
     287               0 :             UpdateRowWithGeometry(row, &oLR);
     288                 :         }
     289               0 :         else if ( eType == wkbPolygon )
     290                 :         {
     291               0 :             OGRPolygon oPoly;
     292               0 :             oPoly.addRing(&oLR);
     293                 : 
     294               0 :             UpdateRowWithGeometry(row, &oPoly);
     295                 :         }
     296               0 :         else if ( eType == wkbMultiPoint )
     297                 :         {
     298               0 :             OGRMultiPoint oColl;
     299               0 :             oColl.addGeometry(&oP1);
     300               0 :             oColl.addGeometry(&oP2);
     301                 : 
     302               0 :             UpdateRowWithGeometry(row, &oColl);
     303                 :         }
     304               0 :         else if ( eType == wkbMultiLineString )
     305                 :         {
     306               0 :             OGRMultiLineString oColl;
     307               0 :             oColl.addGeometry(&oLR);
     308                 : 
     309               0 :             UpdateRowWithGeometry(row, &oColl);
     310                 :         }
     311               0 :         else if ( eType == wkbMultiPolygon )
     312                 :         {
     313               0 :             OGRMultiPolygon oColl;
     314               0 :             OGRPolygon oPoly;
     315               0 :             oPoly.addRing(&oLR);
     316               0 :             oColl.addGeometry(&oPoly);
     317                 : 
     318               0 :             UpdateRowWithGeometry(row, &oColl);
     319                 :         }
     320                 :         else
     321                 :             return;
     322                 : 
     323                 :         /* Restore original ShapeBuffer */
     324               0 :         hr = row.SetGeometry(originalGdbGeometry);
     325               0 :         if (FAILED(hr))
     326                 :             return;
     327                 : 
     328                 :         /* Update Row */
     329               0 :         hr = m_pTable->Update(row);
     330               0 :         if (FAILED(hr))
     331                 :             return;
     332                 : 
     333               0 :         CPLDebug("FGDB", "Workaround extent problem with Linux 64bit FGDB SDK 1.1");
     334                 :     }
     335                 : }
     336                 : #endif // EXTENT_WORKAROUND
     337                 : 
     338                 : /************************************************************************/
     339                 : /*                            CreateFeature()                           */
     340                 : /* Create an FGDB Row and populate it from an OGRFeature.               */
     341                 : /*                                                                      */
     342                 : /************************************************************************/
     343                 : 
     344            1102 : OGRErr FGdbLayer::CreateFeature( OGRFeature *poFeature )
     345                 : {
     346            1102 :     Table *fgdb_table = m_pTable;
     347            1102 :     Row fgdb_row;
     348                 :     fgdbError hr;
     349                 : 
     350            1102 :     if (m_bBulkLoadAllowed < 0)
     351              34 :         m_bBulkLoadAllowed = CSLTestBoolean(CPLGetConfigOption("FGDB_BULK_LOAD", "NO"));
     352                 : 
     353            1102 :     if (m_bBulkLoadAllowed && !m_bBulkLoadInProgress)
     354               1 :         StartBulkLoad();
     355                 : 
     356            1102 :     hr = fgdb_table->CreateRowObject(fgdb_row);
     357                 : 
     358                 :     /* Check the status of the Row create */
     359            1102 :     if (FAILED(hr))
     360                 :     {
     361               0 :         GDBErr(hr, "Failed at creating Row in CreateFeature.");
     362               0 :         return OGRERR_FAILURE;
     363                 :     }
     364                 : 
     365                 :     /* Populate the row with the feature content */
     366            1102 :     if (PopulateRowWithFeature(fgdb_row, poFeature) != OGRERR_NONE)
     367               0 :         return OGRERR_FAILURE;
     368                 : 
     369                 :     /* Cannot write to FID field - it is managed by GDB*/
     370                 :     //std::wstring wfield_name = StringToWString(m_strOIDFieldName);
     371                 :     //hr = fgdb_row.SetInteger(wfield_name, poFeature->GetFID());
     372                 : 
     373                 :     /* Write the row to the table */
     374            1102 :     hr = fgdb_table->Insert(fgdb_row);
     375            1102 :     if (FAILED(hr))
     376                 :     {
     377               0 :         GDBErr(hr, "Failed at writing Row to Table in CreateFeature.");
     378               0 :         return OGRERR_FAILURE;
     379                 :     }
     380                 : 
     381            1102 :     int32 oid = -1;
     382            1102 :     if (!FAILED(hr = fgdb_row.GetOID(oid)))
     383                 :     {
     384            1102 :         poFeature->SetFID(oid);
     385                 :     }
     386                 : 
     387                 : #ifdef EXTENT_WORKAROUND
     388                 :     /* For WorkAroundExtentProblem() needs */
     389            1102 :     OGRGeometry* poGeom = poFeature->GetGeometryRef();
     390            1102 :     if ( m_bLayerJustCreated && poGeom != NULL && !poGeom->IsEmpty() )
     391                 :     {
     392            1070 :         OGREnvelope sFeatureGeomEnvelope;
     393            1070 :         poGeom->getEnvelope(&sFeatureGeomEnvelope);
     394            1070 :         if (!m_bLayerEnvelopeValid)
     395                 :         {
     396              14 :             memcpy(&sLayerEnvelope, &sFeatureGeomEnvelope, sizeof(sLayerEnvelope));
     397              14 :             m_bLayerEnvelopeValid = true;
     398                 :         }
     399                 :         else
     400                 :         {
     401            1056 :             sLayerEnvelope.Merge(sFeatureGeomEnvelope);
     402                 :         }
     403                 :     }
     404                 : #endif
     405                 : 
     406            1102 :     return OGRERR_NONE;
     407                 : }
     408                 : 
     409                 : /************************************************************************/
     410                 : /*                    PopulateRowWithFeature()                          */
     411                 : /*                                                                      */
     412                 : /************************************************************************/
     413                 : 
     414            1167 : OGRErr FGdbLayer::PopulateRowWithFeature( Row& fgdb_row, OGRFeature *poFeature )
     415                 : {
     416            1167 :     ShapeBuffer shape;
     417                 :     fgdbError hr;
     418                 : 
     419            1167 :     OGRFeatureDefn* poFeatureDefn = m_pFeatureDefn;
     420            1167 :     int nFieldCount = poFeatureDefn->GetFieldCount();
     421                 : 
     422                 :     /* Copy the OGR visible fields (everything except geometry and FID) */
     423            1167 :     for( int i = 0; i < nFieldCount; i++ )
     424                 :     {
     425            1658 :         std::string field_name = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
     426            1658 :         std::wstring wfield_name = StringToWString(field_name);
     427                 : 
     428                 :         /* Set empty fields to NULL */
     429            1658 :         if( !poFeature->IsFieldSet( i ) )
     430                 :         {
     431               6 :             if (FAILED(hr = fgdb_row.SetNull(wfield_name)))
     432                 :             {
     433               0 :                 GDBErr(hr, "Failed setting field to NULL.");
     434               0 :                 return OGRERR_FAILURE;
     435                 :             }
     436               6 :             continue;
     437                 :         }
     438                 : 
     439                 :         /* Set the information using the appropriate FGDB function */
     440            1652 :         int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
     441            1652 :         const std::string & strFieldType = m_vOGRFieldToESRIFieldType[i];
     442                 : 
     443            1652 :         if ( nOGRFieldType == OFTInteger )
     444                 :         {
     445            1304 :             int fldvalue = poFeature->GetFieldAsInteger(i);
     446            1304 :             if( strFieldType == "esriFieldTypeInteger" )
     447            1303 :                 hr = fgdb_row.SetInteger(wfield_name, fldvalue);
     448                 :             else
     449                 :             {
     450               1 :                 if( fldvalue < -32768 || fldvalue > 32767 )
     451                 :                 {
     452                 :                     static int bHasWarned = FALSE;
     453               0 :                     if( !bHasWarned )
     454                 :                     {
     455               0 :                         bHasWarned = TRUE;
     456                 :                         CPLError(CE_Warning, CPLE_NotSupported,
     457                 :                                  "Value %d for field %s does not fit into a short and will be clamped. "
     458                 :                                  "This warning will not be emitted any more",
     459               0 :                                  fldvalue, field_name.c_str());
     460                 :                     }
     461               0 :                     if( fldvalue < -32768 )
     462               0 :                         fldvalue = -32768;
     463                 :                     else
     464               0 :                         fldvalue = 32767;
     465                 :                 }
     466               1 :                 hr = fgdb_row.SetShort(wfield_name, (short) fldvalue);
     467                 :             }
     468                 :         }
     469             348 :         else if ( nOGRFieldType == OFTReal )
     470                 :         {
     471                 :             /* Doubles (we don't handle FGDB Floats) */
     472             183 :             double fldvalue = poFeature->GetFieldAsDouble(i);
     473             183 :             if( strFieldType == "esriFieldTypeDouble" )
     474             182 :                 hr = fgdb_row.SetDouble(wfield_name, fldvalue);
     475                 :             else
     476               1 :                 hr = fgdb_row.SetFloat(wfield_name, (float) fldvalue);
     477                 :         }
     478             165 :         else if ( nOGRFieldType == OFTString )
     479                 :         {
     480                 :             /* Strings we convert to wstring */
     481             164 :             std::string fldvalue = poFeature->GetFieldAsString(i);
     482             164 :             std::wstring wfldvalue = StringToWString(fldvalue);
     483             164 :             if( strFieldType == "esriFieldTypeString" )
     484             162 :                 hr = fgdb_row.SetString(wfield_name, wfldvalue);
     485                 :             // Apparently, esriFieldTypeGlobalID can not be set, but is
     486                 :             // initialized by the FileGDB SDK itself.
     487               2 :             else if( strFieldType == "esriFieldTypeGUID" /*||
     488                 :                      strFieldType == "esriFieldTypeGlobalID" */ )
     489                 :             {
     490               1 :                 Guid guid;
     491               1 :                 if( FAILED(hr = guid.FromString(wfldvalue)) )
     492                 :                 {
     493                 :                     CPLError( CE_Failure, CPLE_AppDefined,
     494                 :                         "Cannot parse GUID value %s for field %s.",
     495               0 :                         fldvalue.c_str(), field_name.c_str() );
     496                 :                 }
     497                 :                 else
     498                 :                 {
     499               1 :                     hr = fgdb_row.SetGUID(wfield_name, guid);
     500               1 :                 }
     501                 :             }
     502                 :             else
     503               1 :                 hr = 0;
     504                 :         }
     505               2 :         else if ( nOGRFieldType == OFTDateTime || nOGRFieldType == OFTDate )
     506                 :         {
     507                 :             /* Dates we need to coerce a little */
     508                 :             struct tm val;
     509                 :             poFeature->GetFieldAsDateTime(i, &(val.tm_year), &(val.tm_mon), &(val.tm_mday),
     510               1 :                                           &(val.tm_hour), &(val.tm_min), &(val.tm_sec), NULL);
     511               1 :             val.tm_year -= 1900;
     512               1 :             val.tm_mon = val.tm_mon - 1; /* OGR months go 1-12, FGDB go 0-11 */
     513               1 :             hr = fgdb_row.SetDate(wfield_name, val);
     514                 :         }
     515               0 :         else if ( nOGRFieldType == OFTBinary )
     516                 :         {
     517                 :             /* Binary data */
     518               0 :             ByteArray fgdb_bytearray;
     519                 :             int bytesize;
     520               0 :             GByte *bytes = poFeature->GetFieldAsBinary(i, &bytesize);
     521               0 :             if ( bytesize )
     522                 :             {
     523               0 :                 fgdb_bytearray.Allocate(bytesize);
     524               0 :                 memcpy(fgdb_bytearray.byteArray, bytes, bytesize);
     525               0 :                 fgdb_bytearray.inUseLength = bytesize;
     526               0 :                 hr = fgdb_row.SetBinary(wfield_name, fgdb_bytearray);
     527                 :             }
     528                 :             else
     529                 :             {
     530               0 :                 hr = fgdb_row.SetNull(wfield_name);
     531               0 :             }
     532                 :         }
     533                 :         else
     534                 :         {
     535                 :             /* We can't handle this type */
     536                 :             CPLError( CE_Failure, CPLE_AppDefined,
     537               0 :                 "FGDB driver does not support OGR type." );
     538               0 :             return OGRERR_FAILURE;
     539                 :         }
     540                 :         
     541            1652 :         if (FAILED(hr))
     542                 :         {
     543                 :             CPLError(CE_Warning, CPLE_AppDefined, "Cannot set value for field %s",
     544               0 :                      field_name.c_str());
     545                 :         }
     546                 :     }
     547                 : 
     548            1167 :     if ( m_pFeatureDefn->GetGeomType() != wkbNone )
     549                 :     {
     550                 :         /* Done with attribute fields, now do geometry */
     551            1155 :         OGRGeometry *poGeom = poFeature->GetGeometryRef();
     552                 : 
     553            1155 :         if (poGeom == NULL || poGeom->IsEmpty())
     554                 :         {
     555                 :             /* EMPTY geometries should be treated as NULL, see #4832 */
     556              20 :             hr = fgdb_row.SetNull(StringToWString(m_strShapeFieldName));
     557              20 :             if (FAILED(hr))
     558                 :             {
     559               0 :                 GDBErr(hr, "Failed at writing EMPTY Geometry to Row in CreateFeature.");
     560               0 :                 return OGRERR_FAILURE;
     561                 :             }
     562                 :         }
     563                 :         else
     564                 :         {
     565                 :             /* Write geometry to a buffer */
     566            1135 :             GByte *pabyShape = NULL;
     567            1135 :             int nShapeSize = 0;
     568            1135 :             OGRErr err = OGRWriteToShapeBin( poGeom, &pabyShape, &nShapeSize );
     569            1135 :             if ( err != OGRERR_NONE )
     570               0 :                 return err;
     571                 : 
     572                 :             /* Copy it into a ShapeBuffer */
     573            1135 :             if ( nShapeSize > 0 )
     574                 :             {
     575            1135 :                 shape.Allocate(nShapeSize);
     576            1135 :                 memcpy(shape.shapeBuffer, pabyShape, nShapeSize);
     577            1135 :                 shape.inUseLength = nShapeSize;
     578                 :             }
     579                 : 
     580                 :             /* Free the shape buffer */
     581            1135 :             CPLFree(pabyShape);
     582                 : 
     583                 :             /* Write ShapeBuffer into the Row */
     584            1135 :             hr = fgdb_row.SetGeometry(shape);
     585            1135 :             if (FAILED(hr))
     586                 :             {
     587               0 :                 GDBErr(hr, "Failed at writing Geometry to Row in CreateFeature.");
     588               0 :                 return OGRERR_FAILURE;
     589                 :             }
     590                 :         }
     591                 :     }
     592                 : 
     593            1167 :     return OGRERR_NONE;
     594                 : 
     595                 : }
     596                 : 
     597                 : /************************************************************************/
     598                 : /*                             GetRow()                                 */
     599                 : /************************************************************************/
     600                 : 
     601             193 : OGRErr FGdbLayer::GetRow( EnumRows& enumRows, Row& row, long nFID )
     602                 : {
     603                 :     long           hr;
     604             193 :     CPLString      osQuery;
     605                 : 
     606             193 :     osQuery.Printf("%s = %ld", m_strOIDFieldName.c_str(), nFID);
     607                 : 
     608             193 :     if (FAILED(hr = m_pTable->Search(m_wstrSubfields, StringToWString(osQuery.c_str()), true, enumRows)))
     609                 :     {
     610               0 :         GDBErr(hr, "Failed fetching row ");
     611               0 :         return OGRERR_FAILURE;
     612                 :     }
     613                 : 
     614             193 :     if (FAILED(hr = enumRows.Next(row)))
     615                 :     {
     616               0 :         GDBErr(hr, "Failed fetching row ");
     617               0 :         return OGRERR_FAILURE;
     618                 :     }
     619                 : 
     620             193 :     if (hr != S_OK)
     621              48 :         return OGRERR_FAILURE; //none found - but no failure
     622                 : 
     623             145 :     return OGRERR_NONE;
     624                 : }
     625                 : 
     626                 : /************************************************************************/
     627                 : /*                           DeleteFeature()                            */
     628                 : /************************************************************************/
     629                 : 
     630              16 : OGRErr FGdbLayer::DeleteFeature( long nFID )
     631                 : 
     632                 : {
     633                 :     long           hr;
     634              16 :     EnumRows       enumRows;
     635              16 :     Row            row;
     636                 : 
     637              16 :     EndBulkLoad();
     638                 : 
     639              16 :     if (GetRow(enumRows, row, nFID) != OGRERR_NONE)
     640               0 :         return OGRERR_FAILURE;
     641                 : 
     642              16 :     if (FAILED(hr = m_pTable->Delete(row)))
     643                 :     {
     644               0 :         GDBErr(hr, "Failed deleting row ");
     645               0 :         return OGRERR_FAILURE;
     646                 :     }
     647                 : 
     648              16 :     return OGRERR_NONE;
     649                 : }
     650                 : 
     651                 : /************************************************************************/
     652                 : /*                            SetFeature()                              */
     653                 : /************************************************************************/
     654                 : 
     655              65 : OGRErr FGdbLayer::SetFeature( OGRFeature* poFeature )
     656                 : 
     657                 : {
     658                 :     long           hr;
     659              65 :     EnumRows       enumRows;
     660              65 :     Row            row;
     661                 : 
     662              65 :     if( poFeature->GetFID() == OGRNullFID )
     663                 :     {
     664                 :         CPLError( CE_Failure, CPLE_AppDefined,
     665               0 :                   "SetFeature() with unset FID fails." );
     666               0 :         return OGRERR_FAILURE;
     667                 :     }
     668                 : 
     669              65 :     EndBulkLoad();
     670                 : 
     671              65 :     if (GetRow(enumRows, row, poFeature->GetFID()) != OGRERR_NONE)
     672               0 :         return OGRERR_FAILURE;
     673                 : 
     674                 :     /* Populate the row with the feature content */
     675              65 :     if (PopulateRowWithFeature(row, poFeature) != OGRERR_NONE)
     676               0 :         return OGRERR_FAILURE;
     677                 : 
     678              65 :     if (FAILED(hr = m_pTable->Update(row)))
     679                 :     {
     680               0 :         GDBErr(hr, "Failed updating row ");
     681               0 :         return OGRERR_FAILURE;
     682                 :     }
     683                 : 
     684              65 :     return OGRERR_NONE;
     685                 : }
     686                 : 
     687                 : /************************************************************************/
     688                 : /*                          CreateFieldDefn()                           */
     689                 : /************************************************************************/
     690                 : 
     691              73 : char* FGdbLayer::CreateFieldDefn(OGRFieldDefn& oField,
     692                 :                                  int bApproxOK,
     693                 :                                  std::string& fieldname_clean,
     694                 :                                  std::string& gdbFieldType)
     695                 : {
     696              73 :     std::string fieldname = oField.GetNameRef();
     697             146 :     std::string fidname = std::string(GetFIDColumn());
     698             146 :     std::string nullable = "true";
     699                 : 
     700                 :     /* Try to map the OGR type to an ESRI type */
     701             146 :     OGRFieldType fldtype = oField.GetType();
     702              73 :     if ( ! OGRToGDBFieldType(fldtype, &gdbFieldType) )
     703                 :     {
     704               0 :         GDBErr(-1, "Failed converting field type.");
     705               0 :         return NULL;
     706                 :     }
     707                 : 
     708              73 :     if (fieldname_clean.size() != 0)
     709                 :     {
     710               0 :         oField.SetName(fieldname_clean.c_str());
     711                 :     }
     712                 :     else
     713                 :     {
     714                 :         /* Clean field names */
     715              73 :         fieldname_clean = FGDBLaunderName(fieldname);
     716                 : 
     717              73 :         if (m_bLaunderReservedKeywords)
     718              73 :             fieldname_clean = FGDBEscapeReservedKeywords(fieldname_clean);
     719                 : 
     720                 :         /* Truncate to 64 characters */
     721              73 :         if (fieldname_clean.size() > 64)
     722               2 :             fieldname_clean.resize(64);
     723                 : 
     724              73 :         std::string temp_fieldname = fieldname_clean;
     725                 : 
     726                 :         /* Ensures uniqueness of field name */
     727              73 :         int numRenames = 1;
     728             149 :         while ((m_pFeatureDefn->GetFieldIndex(temp_fieldname.c_str()) >= 0) && (numRenames < 10))
     729                 :         {
     730               3 :             temp_fieldname = CPLSPrintf("%s_%d", fieldname_clean.substr(0, 62).c_str(), numRenames);
     731               3 :             numRenames ++;
     732                 :         }
     733             146 :         while ((m_pFeatureDefn->GetFieldIndex(temp_fieldname.c_str()) >= 0) && (numRenames < 100))
     734                 :         {
     735               0 :             temp_fieldname = CPLSPrintf("%s_%d", fieldname_clean.substr(0, 61).c_str(), numRenames);
     736               0 :             numRenames ++;
     737                 :         }
     738                 : 
     739              73 :         if (temp_fieldname != fieldname)
     740                 :         {
     741               5 :             if( !bApproxOK || (m_pFeatureDefn->GetFieldIndex(temp_fieldname.c_str()) >= 0) )
     742                 :             {
     743                 :                 CPLError( CE_Failure, CPLE_NotSupported,
     744                 :                     "Failed to add field named '%s'",
     745               0 :                     fieldname.c_str() );
     746               0 :                 return NULL;
     747                 :             }
     748                 :             CPLError(CE_Warning, CPLE_NotSupported,
     749                 :                 "Normalized/laundered field name: '%s' to '%s'",
     750               5 :                 fieldname.c_str(), temp_fieldname.c_str());
     751                 : 
     752               5 :             fieldname_clean = temp_fieldname;
     753               5 :             oField.SetName(fieldname_clean.c_str());
     754               0 :         }
     755                 :     }
     756                 : 
     757                 :     /* Then the Field definition */
     758              73 :     CPLXMLNode *defn_xml = CPLCreateXMLNode(NULL, CXT_Element, "esri:Field");
     759                 : 
     760                 :     /* Add the XML attributes to the Field node */
     761              73 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
     762              73 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:xs", "http://www.w3.org/2001/XMLSchema");
     763              73 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:esri", "http://www.esri.com/schemas/ArcGIS/10.1");
     764              73 :     FGDB_CPLAddXMLAttribute(defn_xml, "xsi:type", "esri:Field");
     765                 : 
     766                 :     /* Basic field information */
     767              73 :     CPLCreateXMLElementAndValue(defn_xml, "Name", fieldname_clean.c_str());
     768              73 :     CPLCreateXMLElementAndValue(defn_xml, "Type", gdbFieldType.c_str());
     769              73 :     CPLCreateXMLElementAndValue(defn_xml, "IsNullable", nullable.c_str());
     770                 : 
     771                 :     /* Get the Width and Precision if we know them */
     772              73 :     int width = oField.GetWidth();
     773              73 :     int precision = oField.GetPrecision();
     774              73 :     if ( width <= 0 )
     775              70 :         GDBFieldTypeToWidthPrecision(gdbFieldType, &width, &precision);
     776                 : 
     777                 :     /* Write out the Width and Precision */
     778                 :     char buf[100];
     779              73 :     snprintf(buf, 100, "%d", width);
     780              73 :     CPLCreateXMLElementAndValue(defn_xml,"Length", buf);
     781              73 :     snprintf(buf, 100, "%d", precision);
     782              73 :     CPLCreateXMLElementAndValue(defn_xml,"Precision", buf);
     783                 : 
     784                 :     /* We know nothing about Scale, so zero it out */
     785              73 :     CPLCreateXMLElementAndValue(defn_xml,"Scale", "0");
     786                 : 
     787                 :     /*  Attempt to preserve the original fieldname */
     788              73 :     if (fieldname != fieldname_clean)
     789                 :     {
     790               5 :         CPLCreateXMLElementAndValue(defn_xml, "AliasName", fieldname.c_str());
     791                 :     }
     792                 : 
     793                 :     /* Default values are discouraged in OGR API docs */
     794                 :     /* <DefaultValue xsi:type="xs:string">afternoon</DefaultValue> */
     795                 : 
     796                 :     /* Convert our XML tree into a string for FGDB */
     797              73 :     char *defn_str = CPLSerializeXMLTree(defn_xml);
     798              73 :     CPLDebug("FGDB", "CreateField() generated XML for FGDB\n%s", defn_str);
     799                 : 
     800                 :     /* Free the XML */
     801              73 :     CPLDestroyXMLNode(defn_xml);
     802                 : 
     803              73 :     return defn_str;
     804                 : }
     805                 : 
     806                 : /************************************************************************/
     807                 : /*                            CreateField()                             */
     808                 : /*  Build up an FGDB XML field definition and use it to create a Field  */
     809                 : /*  Update the OGRFeatureDefn to reflect the new field.                 */
     810                 : /*                                                                      */
     811                 : /************************************************************************/
     812                 : 
     813              73 : OGRErr FGdbLayer::CreateField(OGRFieldDefn* poField, int bApproxOK)
     814                 : {
     815              73 :     OGRFieldDefn oField(poField);
     816              73 :     std::string fieldname_clean;
     817              73 :     std::string gdbFieldType;
     818                 : 
     819                 :     char* defn_str = CreateFieldDefn(oField, bApproxOK,
     820              73 :                                      fieldname_clean, gdbFieldType);
     821              73 :     if (defn_str == NULL)
     822               0 :         return OGRERR_FAILURE;
     823                 : 
     824                 :     /* Add the FGDB Field to the FGDB Table. */
     825              73 :     fgdbError hr = m_pTable->AddField(defn_str);
     826                 : 
     827              73 :     CPLFree(defn_str);
     828                 : 
     829                 :     /* Check the status of the Field add */
     830              73 :     if (FAILED(hr))
     831                 :     {
     832               0 :         GDBErr(hr, "Failed at creating Field for " + std::string(oField.GetNameRef()));
     833               0 :         return OGRERR_FAILURE;
     834                 :     }
     835                 : 
     836                 :     /* Now add the OGRFieldDefn to the OGRFeatureDefn */
     837              73 :     m_pFeatureDefn->AddFieldDefn(&oField);
     838                 : 
     839              73 :     m_vOGRFieldToESRIField.push_back(StringToWString(fieldname_clean));
     840              73 :     m_vOGRFieldToESRIFieldType.push_back( gdbFieldType );
     841                 : 
     842                 :     /* All done and happy */
     843              73 :     return OGRERR_NONE;
     844                 : 
     845                 : }
     846                 : 
     847                 : /************************************************************************/
     848                 : /*                             DeleteField()                            */
     849                 : /************************************************************************/
     850                 : 
     851               1 : OGRErr FGdbLayer::DeleteField( int iFieldToDelete )
     852                 : {
     853               1 :     if (iFieldToDelete < 0 || iFieldToDelete >= m_pFeatureDefn->GetFieldCount())
     854                 :     {
     855                 :         CPLError( CE_Failure, CPLE_NotSupported,
     856               0 :                   "Invalid field index");
     857               0 :         return OGRERR_FAILURE;
     858                 :     }
     859                 : 
     860               1 :     ResetReading();
     861                 : 
     862               1 :     const char* pszFieldName = m_pFeatureDefn->GetFieldDefn(iFieldToDelete)->GetNameRef();
     863                 : 
     864                 :     fgdbError hr;
     865               1 :     if (FAILED(hr = m_pTable->DeleteField(StringToWString(pszFieldName))))
     866                 :     {
     867               0 :         GDBErr(hr, "Failed deleting field " + std::string(pszFieldName));
     868               0 :         return OGRERR_FAILURE;
     869                 :     }
     870                 : 
     871               1 :     m_vOGRFieldToESRIField.erase (m_vOGRFieldToESRIField.begin() + iFieldToDelete);
     872               1 :     m_vOGRFieldToESRIFieldType.erase( m_vOGRFieldToESRIFieldType.begin() + iFieldToDelete );
     873                 : 
     874                 : 
     875               1 :     return m_pFeatureDefn->DeleteFieldDefn( iFieldToDelete );
     876                 : }
     877                 : 
     878                 : #ifdef AlterFieldDefn_implemented_but_not_working
     879                 : 
     880                 : /************************************************************************/
     881                 : /*                           AlterFieldDefn()                           */
     882                 : /************************************************************************/
     883                 : 
     884                 : OGRErr FGdbLayer::AlterFieldDefn( int iFieldToAlter, OGRFieldDefn* poNewFieldDefn, int nFlags )
     885                 : {
     886                 :     if (iFieldToAlter < 0 || iFieldToAlter >= m_pFeatureDefn->GetFieldCount())
     887                 :     {
     888                 :         CPLError( CE_Failure, CPLE_NotSupported,
     889                 :                   "Invalid field index");
     890                 :         return OGRERR_FAILURE;
     891                 :     }
     892                 : 
     893                 :     OGRFieldDefn* poFieldDefn = m_pFeatureDefn->GetFieldDefn(iFieldToAlter);
     894                 :     OGRFieldDefn oField(poFieldDefn);
     895                 : 
     896                 :     if (nFlags & ALTER_TYPE_FLAG)
     897                 :         oField.SetType(poNewFieldDefn->GetType());
     898                 :     if (nFlags & ALTER_NAME_FLAG)
     899                 :     {
     900                 :         if (strcmp(poNewFieldDefn->GetNameRef(), oField.GetNameRef()) != 0)
     901                 :         {
     902                 :             CPLError( CE_Failure, CPLE_NotSupported,
     903                 :                       "Altering field name is not supported" );
     904                 :             return OGRERR_FAILURE;
     905                 :         }
     906                 :         oField.SetName(poNewFieldDefn->GetNameRef());
     907                 :     }
     908                 :     if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
     909                 :     {
     910                 :         oField.SetWidth(poNewFieldDefn->GetWidth());
     911                 :         oField.SetPrecision(poNewFieldDefn->GetPrecision());
     912                 :     }
     913                 : 
     914                 :     std::string fieldname_clean = WStringToString(m_vOGRFieldToESRIField[iFieldToAlter]);
     915                 :     std::string gdbFieldType;
     916                 : 
     917                 :     char* defn_str = CreateFieldDefn(oField, TRUE,
     918                 :                                      fieldname_clean, gdbFieldType);
     919                 :     if (defn_str == NULL)
     920                 :         return OGRERR_FAILURE;
     921                 : 
     922                 :     ResetReading();
     923                 : 
     924                 :     /* Add the FGDB Field to the FGDB Table. */
     925                 :     fgdbError hr = m_pTable->AlterField(defn_str);
     926                 : 
     927                 :     CPLFree(defn_str);
     928                 : 
     929                 :     /* Check the status of the AlterField */
     930                 :     if (FAILED(hr))
     931                 :     {
     932                 :         GDBErr(hr, "Failed at altering field " + std::string(oField.GetNameRef()));
     933                 :         return OGRERR_FAILURE;
     934                 :     }
     935                 : 
     936                 :     m_vOGRFieldToESRIFieldType[iFieldToAlter] = gdbFieldType;
     937                 : 
     938                 :     poFieldDefn->SetType(oField.GetType());
     939                 :     poFieldDefn->SetWidth(oField.GetWidth());
     940                 :     poFieldDefn->SetPrecision(oField.GetPrecision());
     941                 : 
     942                 :     return OGRERR_NONE;
     943                 : }
     944                 : #endif // AlterFieldDefn_implemented_but_not_working
     945                 : 
     946                 : /************************************************************************/
     947                 : /*                      XMLSpatialReference()                           */
     948                 : /*  Build up an XML representation of an OGRSpatialReference.           */
     949                 : /*  Used in layer creation.                                             */
     950                 : /*                                                                      */
     951                 : /************************************************************************/
     952                 : 
     953              37 : CPLXMLNode* XMLSpatialReference(OGRSpatialReference* poSRS, char** papszOptions)
     954                 : {
     955                 :     /* We always need a SpatialReference */
     956              37 :     CPLXMLNode *srs_xml = CPLCreateXMLNode(NULL, CXT_Element, "SpatialReference");
     957                 : 
     958                 :     /* Extract the WKID before morphing */
     959              37 :     int nSRID = 0;
     960              37 :     if ( poSRS && poSRS->GetAuthorityCode(NULL) )
     961                 :     {
     962              31 :         nSRID = atoi(poSRS->GetAuthorityCode(NULL));
     963                 :     }
     964                 : 
     965                 :     /* NULL poSRS => UnknownCoordinateSystem */
     966              37 :     if ( ! poSRS )
     967                 :     {
     968               1 :         FGDB_CPLAddXMLAttribute(srs_xml, "xsi:type", "esri:UnknownCoordinateSystem");
     969                 :     }
     970                 :     else
     971                 :     {
     972                 :         /* Set the SpatialReference type attribute correctly for GEOGCS/PROJCS */
     973              36 :         if ( poSRS->IsProjected() )
     974               3 :             FGDB_CPLAddXMLAttribute(srs_xml, "xsi:type", "esri:ProjectedCoordinateSystem");
     975                 :         else
     976              33 :             FGDB_CPLAddXMLAttribute(srs_xml, "xsi:type", "esri:GeographicCoordinateSystem");
     977                 : 
     978                 :         /* Add the WKT to the XML */
     979              36 :         SpatialReferenceInfo oESRI_SRS;
     980                 : 
     981                 :         /* Do we have a known SRID ? If so, directly query the ESRI SRS DB */
     982              36 :         if( nSRID && SpatialReferences::FindSpatialReferenceBySRID(nSRID, oESRI_SRS) )
     983                 :         {
     984                 :             CPLDebug("FGDB",
     985                 :                      "Layer SRS has a SRID (%d). Using WKT from ESRI SRS DBFound perfect match. ",
     986              30 :                      nSRID);
     987              30 :             CPLCreateXMLElementAndValue(srs_xml,"WKT", WStringToString(oESRI_SRS.srtext).c_str());
     988                 :         }
     989                 :         else
     990                 :         {
     991                 :             /* Make a clone so we can morph it without morphing the original */
     992               6 :             OGRSpatialReference* poSRSClone = poSRS->Clone();
     993                 : 
     994                 :             /* Flip the WKT to ESRI form, return UnknownCoordinateSystem if we can't */
     995               6 :             if ( poSRSClone->morphToESRI() != OGRERR_NONE )
     996                 :             {
     997               0 :                 delete poSRSClone;
     998               0 :                 FGDB_CPLAddXMLAttribute(srs_xml, "xsi:type", "esri:UnknownCoordinateSystem");
     999               0 :                 return srs_xml;
    1000                 :             }
    1001                 : 
    1002               6 :             char *wkt = NULL;
    1003               6 :             poSRSClone->exportToWkt(&wkt);
    1004               6 :             if (wkt)
    1005                 :             {
    1006               6 :                 EnumSpatialReferenceInfo oEnumESRI_SRS;
    1007               6 :                 std::vector<int> oaiCandidateSRS;
    1008               6 :                 nSRID = 0;
    1009                 : 
    1010                 :                 /* Enumerate SRS from ESRI DB and find a match */
    1011           11168 :                 while(TRUE)
    1012                 :                 {
    1013           11174 :                     if ( poSRS->IsProjected() )
    1014                 :                     {
    1015            8494 :                         if( !oEnumESRI_SRS.NextProjectedSpatialReference(oESRI_SRS) )
    1016               2 :                             break;
    1017                 :                     }
    1018                 :                     else
    1019                 :                     {
    1020            2680 :                         if( !oEnumESRI_SRS.NextGeographicSpatialReference(oESRI_SRS) )
    1021               4 :                             break;
    1022                 :                     }
    1023                 : 
    1024           11168 :                     std::string osESRI_WKT = WStringToString(oESRI_SRS.srtext);
    1025           11168 :                     const char* pszESRI_WKT = osESRI_WKT.c_str();
    1026           11168 :                     if( strcmp(pszESRI_WKT, wkt) == 0 )
    1027                 :                     {
    1028                 :                         /* Exact match found (not sure this case happens) */
    1029               0 :                         nSRID = oESRI_SRS.auth_srid;
    1030                 :                         break;
    1031                 :                     }
    1032           11168 :                     OGRSpatialReference oSRS_FromESRI;
    1033           11168 :                     if( oSRS_FromESRI.SetFromUserInput(pszESRI_WKT) == OGRERR_NONE &&
    1034                 :                         poSRSClone->IsSame(&oSRS_FromESRI) )
    1035                 :                     {
    1036                 :                         /* Potential match found */
    1037               3 :                         oaiCandidateSRS.push_back(oESRI_SRS.auth_srid);
    1038                 :                     }
    1039                 :                 }
    1040                 : 
    1041               6 :                 if( nSRID != 0 )
    1042                 :                 {
    1043                 :                     CPLDebug("FGDB",
    1044                 :                              "Found perfect match in ESRI SRS DB "
    1045               0 :                              "for layer SRS. SRID is %d", nSRID);
    1046                 :                 }
    1047               6 :                 else if( oaiCandidateSRS.size() == 0 )
    1048                 :                 {
    1049                 :                      CPLDebug("FGDB",
    1050                 :                               "Did not found a match in ESRI SRS DB for layer SRS. "
    1051               3 :                               "Using morphed SRS WKT. Failure is to be expected");
    1052                 :                 }
    1053               3 :                 else if( oaiCandidateSRS.size() == 1 )
    1054                 :                 {
    1055               3 :                     nSRID = oaiCandidateSRS[0];
    1056               3 :                     if( SpatialReferences::FindSpatialReferenceBySRID(
    1057                 :                                                             nSRID, oESRI_SRS) )
    1058                 :                     {
    1059                 :                         CPLDebug("FGDB",
    1060                 :                                  "Found a single match in ESRI SRS DB "
    1061                 :                                  "for layer SRS. SRID is %d",
    1062               3 :                                  nSRID);
    1063               3 :                         nSRID = oESRI_SRS.auth_srid;
    1064               3 :                         OGRFree(wkt);
    1065               3 :                         wkt = CPLStrdup(WStringToString(oESRI_SRS.srtext).c_str());
    1066                 :                     }
    1067                 :                 }
    1068                 :                 else
    1069                 :                 {
    1070                 :                     /* Not sure this case can happen */
    1071                 : 
    1072               0 :                     CPLString osCandidateSRS;
    1073               0 :                     for(int i=0; i<(int)oaiCandidateSRS.size() && i < 10; i++)
    1074                 :                     {
    1075               0 :                         if( osCandidateSRS.size() )
    1076               0 :                             osCandidateSRS += ", ";
    1077               0 :                         osCandidateSRS += CPLSPrintf("%d", oaiCandidateSRS[i]);
    1078                 :                     }
    1079               0 :                     if(oaiCandidateSRS.size() > 10)
    1080               0 :                         osCandidateSRS += "...";
    1081                 : 
    1082                 :                     CPLDebug("FGDB",
    1083                 :                              "As several candidates (%s) have been found in "
    1084                 :                              "ESRI SRS DB for layer SRS, none has been selected. "
    1085                 :                              "Using morphed SRS WKT. Failure is to be expected",
    1086               0 :                              osCandidateSRS.c_str());
    1087                 :                 }
    1088                 : 
    1089               6 :                 CPLCreateXMLElementAndValue(srs_xml,"WKT", wkt);
    1090               6 :                 OGRFree(wkt);
    1091                 :             }
    1092                 : 
    1093                 :             /* Dispose of our close */
    1094               6 :             delete poSRSClone;
    1095               0 :         }
    1096                 :     }
    1097                 :     
    1098                 :     /* Handle Origin/Scale/Tolerance */
    1099                 :     const char* grid[7] = {
    1100                 :       "XOrigin", "YOrigin", "XYScale",
    1101                 :       "ZOrigin", "ZScale",
    1102              37 :       "XYTolerance", "ZTolerance" };
    1103                 :     const char* gridvalues[7];
    1104                 : 
    1105                 :     /* 
    1106                 :     Need different default paramters for geographic and projected coordinate systems.
    1107                 :     Try and use ArcGIS 10 default values.
    1108                 :     */
    1109                 :     // default tolerance is 1mm in the units of the coordinate system
    1110              37 :     double ztol = 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("VERT_CS") : 1.0);
    1111                 :     // default scale is 10x the tolerance
    1112              37 :     long zscale = 1 / ztol * 10;
    1113                 : 
    1114                 :     char s_xyscale[50], s_xytol[50], s_zscale[50], s_ztol[50];
    1115              37 :     snprintf(s_ztol, 50, "%f", ztol);
    1116              37 :     snprintf(s_zscale, 50, "%ld", zscale);
    1117                 :     
    1118              37 :     if ( poSRS == NULL || poSRS->IsProjected() )
    1119                 :     {
    1120                 :         // default tolerance is 1mm in the units of the coordinate system
    1121               4 :         double xytol = 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("PROJCS") : 1.0);
    1122                 :         // default scale is 10x the tolerance
    1123               4 :         long xyscale = 1 / xytol * 10;
    1124                 : 
    1125               4 :         snprintf(s_xytol, 50, "%f", xytol);
    1126               4 :         snprintf(s_xyscale, 50, "%ld", xyscale);
    1127                 : 
    1128                 :         // Ideally we would use the same X/Y origins as ArcGIS, but we need the algorithm they use.
    1129               4 :         gridvalues[0] = "-2147483647";
    1130               4 :         gridvalues[1] = "-2147483647";
    1131               4 :         gridvalues[2] = s_xyscale;
    1132               4 :         gridvalues[3] = "-100000";
    1133               4 :         gridvalues[4] = s_zscale;
    1134               4 :         gridvalues[5] = s_xytol;
    1135               4 :         gridvalues[6] = s_ztol;
    1136                 :     }
    1137                 :     else
    1138                 :     {
    1139              33 :         gridvalues[0] = "-400";
    1140              33 :         gridvalues[1] = "-400";
    1141              33 :         gridvalues[2] = "1000000000";
    1142              33 :         gridvalues[3] = "-100000";
    1143              33 :         gridvalues[4] = s_zscale;
    1144              33 :         gridvalues[5] = "0.000000008983153";
    1145              33 :         gridvalues[6] = s_ztol;
    1146                 :     }
    1147                 : 
    1148                 :     /* Convert any layer creation options available, use defaults otherwise */
    1149             296 :     for( int i = 0; i < 7; i++ )
    1150                 :     {
    1151             259 :         if ( CSLFetchNameValue( papszOptions, grid[i] ) != NULL )
    1152               0 :             gridvalues[i] = CSLFetchNameValue( papszOptions, grid[i] );
    1153                 : 
    1154             259 :         CPLCreateXMLElementAndValue(srs_xml, grid[i], gridvalues[i]);
    1155                 :     }
    1156                 : 
    1157                 :     /* FGDB is always High Precision */
    1158              37 :     CPLCreateXMLElementAndValue(srs_xml, "HighPrecision", "true");     
    1159                 : 
    1160                 :     /* Add the WKID to the XML */
    1161              37 :     if ( nSRID ) 
    1162                 :     {
    1163              33 :         CPLCreateXMLElementAndValue(srs_xml, "WKID", CPLSPrintf("%d", nSRID));
    1164                 :     }
    1165                 : 
    1166              37 :     return srs_xml;
    1167                 : }
    1168                 : 
    1169                 : /************************************************************************/
    1170                 : /*                    CreateFeatureDataset()                            */
    1171                 : /************************************************************************/
    1172                 : 
    1173               1 : bool FGdbLayer::CreateFeatureDataset(FGdbDataSource* pParentDataSource, 
    1174                 :                                      std::string feature_dataset_name,
    1175                 :                                      OGRSpatialReference* poSRS,
    1176                 :                                      char** papszOptions )
    1177                 : {
    1178                 :     /* XML node */
    1179               1 :     CPLXMLNode *xml_xml = CPLCreateXMLNode(NULL, CXT_Element, "?xml");
    1180               1 :     FGDB_CPLAddXMLAttribute(xml_xml, "version", "1.0");
    1181               1 :     FGDB_CPLAddXMLAttribute(xml_xml, "encoding", "UTF-8");
    1182                 : 
    1183                 :     /* First build up a bare-bones feature definition */
    1184               1 :     CPLXMLNode *defn_xml = CPLCreateXMLNode(NULL, CXT_Element, "esri:DataElement");
    1185               1 :     CPLAddXMLSibling(xml_xml, defn_xml);
    1186                 : 
    1187                 :     /* Add the attributes to the DataElement */
    1188               1 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    1189               1 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:xs", "http://www.w3.org/2001/XMLSchema");
    1190               1 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:esri", "http://www.esri.com/schemas/ArcGIS/10.1");
    1191                 : 
    1192                 :     /* Need to set this to esri:DEFeatureDataset or esri:DETable */
    1193               1 :     FGDB_CPLAddXMLAttribute(defn_xml, "xsi:type", "esri:DEFeatureDataset");
    1194                 : 
    1195                 :     /* Add in more children */
    1196               1 :     std::string catalog_page = "\\" + feature_dataset_name;
    1197               1 :     CPLCreateXMLElementAndValue(defn_xml,"CatalogPath", catalog_page.c_str());
    1198               1 :     CPLCreateXMLElementAndValue(defn_xml,"Name", feature_dataset_name.c_str());
    1199               1 :     CPLCreateXMLElementAndValue(defn_xml,"ChildrenExpanded", "false");
    1200               1 :     CPLCreateXMLElementAndValue(defn_xml,"DatasetType", "esriDTFeatureDataset");
    1201               1 :     CPLCreateXMLElementAndValue(defn_xml,"Versioned", "false");
    1202               1 :     CPLCreateXMLElementAndValue(defn_xml,"CanVersion", "false");
    1203                 : 
    1204                 :     /* Add in empty extent */
    1205               1 :     CPLXMLNode *extent_xml = CPLCreateXMLNode(NULL, CXT_Element, "Extent");
    1206               1 :     FGDB_CPLAddXMLAttribute(extent_xml, "xsi:nil", "true");
    1207               1 :     CPLAddXMLChild(defn_xml, extent_xml);
    1208                 : 
    1209                 :     /* Add the SRS */
    1210                 :     if( TRUE ) // TODO: conditional on existence of SRS
    1211                 :     {
    1212               1 :         CPLXMLNode *srs_xml = XMLSpatialReference(poSRS, papszOptions);
    1213               1 :         if ( srs_xml )
    1214               1 :             CPLAddXMLChild(defn_xml, srs_xml);
    1215                 :     }
    1216                 : 
    1217                 :     /* Convert our XML tree into a string for FGDB */
    1218               1 :     char *defn_str = CPLSerializeXMLTree(xml_xml);
    1219               1 :     CPLDestroyXMLNode(xml_xml);
    1220                 : 
    1221                 :     /* TODO, tie this to debugging levels */
    1222               1 :     CPLDebug("FGDB", "%s", defn_str);
    1223                 : 
    1224                 :     /* Create the FeatureDataset. */
    1225               1 :     Geodatabase *gdb = pParentDataSource->GetGDB();
    1226               1 :     fgdbError hr = gdb->CreateFeatureDataset(defn_str);
    1227                 : 
    1228                 :     /* Free the XML */
    1229               1 :     CPLFree(defn_str);
    1230                 : 
    1231                 :     /* Check table create status */
    1232               1 :     if (FAILED(hr))
    1233                 :     {
    1234               0 :         return GDBErr(hr, "Failed at creating FeatureDataset " + feature_dataset_name);
    1235                 :     }
    1236                 : 
    1237               1 :     return true;
    1238                 : }
    1239                 : 
    1240                 : /************************************************************************/
    1241                 : /*                            Create()                                  */
    1242                 : /* Build up an FGDB XML layer definition and use it to create a Table   */
    1243                 : /* or Feature Class to work from.                                       */
    1244                 : /*                                                                      */
    1245                 : /* Layer creation options:                                              */
    1246                 : /*   FEATURE_DATASET, nest layer inside a FeatureDataset folder         */
    1247                 : /*   GEOMETRY_NAME, user-selected name for the geometry column          */
    1248                 : /*   OID_NAME, user-selected name for the FID column                    */
    1249                 : /*   XORIGIN, YORIGIN, ZORIGIN, origin of the snapping grid             */
    1250                 : /*   XYSCALE, ZSCALE, inverse resolution of the snapping grid           */
    1251                 : /*   XYTOLERANCE, ZTOLERANCE, snapping tolerance for topology/networks  */
    1252                 : /*                                                                      */
    1253                 : /************************************************************************/
    1254                 : 
    1255              38 : bool FGdbLayer::Create(FGdbDataSource* pParentDataSource, 
    1256                 :                        const char* pszLayerNameIn, 
    1257                 :                        OGRSpatialReference* poSRS, 
    1258                 :                        OGRwkbGeometryType eType, 
    1259                 :                        char** papszOptions)
    1260                 : {
    1261              38 :     std::string parent_path = "";
    1262              76 :     std::wstring wtable_path, wparent_path;
    1263              38 :     std::string geometry_name = FGDB_GEOMETRY_NAME;
    1264              76 :     std::string fid_name = FGDB_OID_NAME;
    1265              38 :     std::string esri_type;
    1266              38 :     bool has_z = false;
    1267                 : 
    1268                 : #ifdef EXTENT_WORKAROUND
    1269              38 :     m_bLayerJustCreated = true;
    1270                 : #endif
    1271                 : 
    1272                 :     /* Launder the Layer name */
    1273              38 :     std::string layerName = pszLayerNameIn;
    1274                 : 
    1275              76 :     layerName = FGDBLaunderName(pszLayerNameIn);
    1276              76 :     layerName = FGDBEscapeReservedKeywords(layerName);
    1277              38 :     layerName = FGDBEscapeUnsupportedPrefixes(layerName);
    1278                 : 
    1279              38 :     if (layerName.size() > 160)
    1280               2 :         layerName.resize(160);
    1281                 : 
    1282                 :     /* Ensures uniqueness of layer name */
    1283              38 :     int numRenames = 1;
    1284              79 :     while ((pParentDataSource->GetLayerByName(layerName.c_str()) != NULL) && (numRenames < 10))
    1285                 :     {
    1286               3 :         layerName = CPLSPrintf("%s_%d", layerName.substr(0, 158).c_str(), numRenames);
    1287               3 :         numRenames ++;
    1288                 :     }
    1289              76 :     while ((pParentDataSource->GetLayerByName(layerName.c_str()) != NULL) && (numRenames < 100))
    1290                 :     {
    1291               0 :         layerName = CPLSPrintf("%s_%d", layerName.substr(0, 157).c_str(), numRenames);
    1292               0 :         numRenames ++;
    1293                 :     }
    1294                 : 
    1295              38 :     if (layerName != pszLayerNameIn)
    1296                 :     {
    1297                 :         CPLError(CE_Warning, CPLE_NotSupported,
    1298                 :                 "Normalized/laundered layer name: '%s' to '%s'",
    1299               6 :                 pszLayerNameIn, layerName.c_str());
    1300                 :     }
    1301                 : 
    1302              38 :     std::string table_path = "\\" + std::string(layerName);
    1303                 : 
    1304                 :     /* Handle the FEATURE_DATASET case */
    1305              38 :     if (  CSLFetchNameValue( papszOptions, "FEATURE_DATASET") != NULL )
    1306                 :     {
    1307               2 :         std::string feature_dataset = CSLFetchNameValue( papszOptions, "FEATURE_DATASET");
    1308                 : 
    1309                 :         /* Check if FEATURE_DATASET exists. Otherwise create it */
    1310               2 :         std::vector<wstring> featuredatasets;
    1311               2 :         Geodatabase *gdb = pParentDataSource->GetGDB();
    1312               2 :         int bFeatureDataSetExists = FALSE;
    1313                 :         fgdbError hr;
    1314               2 :         if ( !FAILED(hr = gdb->GetChildDatasets(L"\\", L"Feature Dataset", featuredatasets)) )
    1315                 :         {
    1316               2 :             std::wstring feature_dataset_with_slash = L"\\" + StringToWString(feature_dataset);
    1317               3 :             for ( unsigned int i = 0; i < featuredatasets.size(); i++ )
    1318                 :             {
    1319               1 :                 if (featuredatasets[i] == feature_dataset_with_slash)
    1320               1 :                     bFeatureDataSetExists = TRUE;
    1321               2 :             }
    1322                 :         }
    1323                 : 
    1324               2 :         if (!bFeatureDataSetExists)
    1325                 :         {
    1326               1 :             bool rv = CreateFeatureDataset(pParentDataSource, feature_dataset, poSRS, papszOptions);
    1327               1 :             if ( ! rv )
    1328               0 :                 return rv;
    1329                 :         }
    1330                 : 
    1331               2 :         table_path = "\\" + feature_dataset + table_path;
    1332               2 :         parent_path = "\\" + feature_dataset;
    1333                 :     }
    1334                 : 
    1335                 :     /* Convert table_path into wstring */
    1336              38 :     wtable_path = StringToWString(table_path);
    1337              38 :     wparent_path = StringToWString(parent_path);
    1338                 : 
    1339                 :     /* Over-ride the geometry name if necessary */
    1340              38 :     if ( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
    1341               0 :         geometry_name = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
    1342                 : 
    1343                 :     /* Over-ride the OID name if necessary */
    1344              38 :     if ( CSLFetchNameValue( papszOptions, "OID_NAME") != NULL )
    1345               0 :         fid_name = CSLFetchNameValue( papszOptions, "OID_NAME");
    1346                 : 
    1347                 :     /* Figure out our geometry type */
    1348              38 :     if ( eType != wkbNone )
    1349                 :     {
    1350              36 :         if ( wkbFlatten(eType) == wkbUnknown )
    1351                 :         {
    1352               0 :             return GDBErr(-1, "FGDB layers cannot be created with a wkbUnknown layer geometry type.");
    1353                 :         }
    1354              36 :         if ( ! OGRGeometryToGDB(eType, &esri_type, &has_z) )
    1355               0 :             return GDBErr(-1, "Unable to map OGR type to ESRI type");
    1356                 :     }
    1357                 : 
    1358              38 :     m_bLaunderReservedKeywords = CSLFetchBoolean( papszOptions, "LAUNDER_RESERVED_KEYWORDS", TRUE) == TRUE;
    1359                 : 
    1360                 :     /* XML node */
    1361              38 :     CPLXMLNode *xml_xml = CPLCreateXMLNode(NULL, CXT_Element, "?xml");
    1362              38 :     FGDB_CPLAddXMLAttribute(xml_xml, "version", "1.0");
    1363              38 :     FGDB_CPLAddXMLAttribute(xml_xml, "encoding", "UTF-8");
    1364                 : 
    1365                 :     /* First build up a bare-bones feature definition */
    1366              38 :     CPLXMLNode *defn_xml = CPLCreateXMLNode(NULL, CXT_Element, "esri:DataElement");
    1367              38 :     CPLAddXMLSibling(xml_xml, defn_xml);
    1368                 : 
    1369                 :     /* Add the attributes to the DataElement */
    1370              38 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    1371              38 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:xs", "http://www.w3.org/2001/XMLSchema");
    1372              38 :     FGDB_CPLAddXMLAttribute(defn_xml, "xmlns:esri", "http://www.esri.com/schemas/ArcGIS/10.1");
    1373                 : 
    1374                 :     /* Need to set this to esri:DEFeatureDataset or esri:DETable */
    1375              38 :     FGDB_CPLAddXMLAttribute(defn_xml, "xsi:type", (eType == wkbNone ? "esri:DETable" : "esri:DEFeatureClass"));
    1376                 : 
    1377                 :     /* Add in more children */
    1378              38 :     CPLCreateXMLElementAndValue(defn_xml,"CatalogPath",table_path.c_str());
    1379              38 :     CPLCreateXMLElementAndValue(defn_xml,"Name", layerName.c_str());
    1380              38 :     CPLCreateXMLElementAndValue(defn_xml,"ChildrenExpanded", "false");
    1381                 : 
    1382                 :     /* WKB type of none implies this is a 'Table' otherwise it's a 'Feature Class' */
    1383              38 :     std::string datasettype = (eType == wkbNone ? "esriDTTable" : "esriDTFeatureClass");
    1384              76 :     CPLCreateXMLElementAndValue(defn_xml,"DatasetType", datasettype.c_str() );
    1385              38 :     CPLCreateXMLElementAndValue(defn_xml,"Versioned", "false");
    1386              38 :     CPLCreateXMLElementAndValue(defn_xml,"CanVersion", "false");
    1387                 : 
    1388                 :     /* We might need to make OID optional later, but OGR likes to have a FID */
    1389              38 :     CPLCreateXMLElementAndValue(defn_xml,"HasOID", "true");
    1390              38 :     CPLCreateXMLElementAndValue(defn_xml,"OIDFieldName", fid_name.c_str());
    1391                 : 
    1392                 :     /* Add in empty Fields */
    1393              38 :     CPLXMLNode *fields_xml = CPLCreateXMLNode(defn_xml, CXT_Element, "Fields");
    1394              38 :     FGDB_CPLAddXMLAttribute(fields_xml, "xsi:type", "esri:Fields");
    1395              38 :     CPLXMLNode *fieldarray_xml = CPLCreateXMLNode(fields_xml, CXT_Element, "FieldArray");
    1396              38 :     FGDB_CPLAddXMLAttribute(fieldarray_xml, "xsi:type", "esri:ArrayOfField");
    1397                 : 
    1398                 :     /* Feature Classes have an implicit geometry column, so we'll add it at creation time */
    1399              38 :     CPLXMLNode *srs_xml = NULL;
    1400              38 :     if ( eType != wkbNone )
    1401                 :     {
    1402              36 :         CPLXMLNode *shape_xml = CPLCreateXMLNode(fieldarray_xml, CXT_Element, "Field");
    1403              36 :         FGDB_CPLAddXMLAttribute(shape_xml, "xsi:type", "esri:Field");
    1404              36 :         CPLCreateXMLElementAndValue(shape_xml, "Name", geometry_name.c_str());
    1405              36 :         CPLCreateXMLElementAndValue(shape_xml, "Type", "esriFieldTypeGeometry");
    1406              36 :         CPLCreateXMLElementAndValue(shape_xml, "IsNullable", "true");
    1407              36 :         CPLCreateXMLElementAndValue(shape_xml, "Length", "0");
    1408              36 :         CPLCreateXMLElementAndValue(shape_xml, "Precision", "0");
    1409              36 :         CPLCreateXMLElementAndValue(shape_xml, "Scale", "0");
    1410              36 :         CPLCreateXMLElementAndValue(shape_xml, "Required", "true");
    1411              36 :         CPLXMLNode *geom_xml = CPLCreateXMLNode(shape_xml, CXT_Element, "GeometryDef");
    1412              36 :         FGDB_CPLAddXMLAttribute(geom_xml, "xsi:type", "esri:GeometryDef");
    1413              36 :         CPLCreateXMLElementAndValue(geom_xml, "AvgNumPoints", "0");
    1414              36 :         CPLCreateXMLElementAndValue(geom_xml, "GeometryType", esri_type.c_str());
    1415              36 :         CPLCreateXMLElementAndValue(geom_xml,"HasM", "false");
    1416              36 :         CPLCreateXMLElementAndValue(geom_xml,"HasZ", (has_z ? "true" : "false"));
    1417                 : 
    1418                 :         /* Add the SRS if we have one */
    1419              36 :         srs_xml = XMLSpatialReference(poSRS, papszOptions);
    1420              36 :         if ( srs_xml )
    1421              36 :             CPLAddXMLChild(geom_xml, srs_xml);
    1422                 :     }
    1423                 : 
    1424                 :     /* All (?) Tables and Feature Classes will have an ObjectID */
    1425              38 :     CPLXMLNode *oid_xml = CPLCreateXMLNode(fieldarray_xml, CXT_Element, "Field");
    1426              38 :     FGDB_CPLAddXMLAttribute(oid_xml, "xsi:type", "esri:Field");
    1427              38 :     CPLCreateXMLElementAndValue(oid_xml, "Name", fid_name.c_str());
    1428              38 :     CPLCreateXMLElementAndValue(oid_xml, "Type", "esriFieldTypeOID");
    1429              38 :     CPLCreateXMLElementAndValue(oid_xml, "IsNullable", "false");
    1430              38 :     CPLCreateXMLElementAndValue(oid_xml, "Length", "12");
    1431              38 :     CPLCreateXMLElementAndValue(oid_xml, "Precision", "0");
    1432              38 :     CPLCreateXMLElementAndValue(oid_xml, "Scale", "0");
    1433              38 :     CPLCreateXMLElementAndValue(oid_xml, "Required", "true");
    1434                 : 
    1435                 :     /* Add in empty Indexes */
    1436              38 :     CPLXMLNode *indexes_xml = CPLCreateXMLNode(defn_xml, CXT_Element, "Indexes");
    1437              38 :     FGDB_CPLAddXMLAttribute(indexes_xml, "xsi:type", "esri:Indexes");
    1438              38 :     CPLXMLNode *indexarray_xml = CPLCreateXMLNode(indexes_xml, CXT_Element, "IndexArray");
    1439              38 :     FGDB_CPLAddXMLAttribute(indexarray_xml, "xsi:type", "esri:ArrayOfIndex");
    1440                 : 
    1441                 :     /* CLSID http://forums.arcgis.com/threads/34536?p=118484#post118484 */
    1442              38 :     if ( eType == wkbNone )
    1443                 :     {
    1444               2 :         CPLCreateXMLElementAndValue(defn_xml, "CLSID", "{7A566981-C114-11D2-8A28-006097AFF44E}");
    1445               2 :         CPLCreateXMLElementAndValue(defn_xml, "EXTCLSID", "");
    1446                 :     }
    1447                 :     else
    1448                 :     {
    1449              36 :         CPLCreateXMLElementAndValue(defn_xml, "CLSID", "{52353152-891A-11D0-BEC6-00805F7C4268}");
    1450              36 :         CPLCreateXMLElementAndValue(defn_xml, "EXTCLSID", "");
    1451                 :     }
    1452                 : 
    1453                 :     /* Set the alias for the Feature Class */
    1454              38 :     if (pszLayerNameIn != layerName)
    1455                 :     {
    1456               6 :         CPLCreateXMLElementAndValue(defn_xml, "AliasName", pszLayerNameIn);
    1457                 :     }
    1458                 : 
    1459                 :     /* Map from OGR WKB type to ESRI type */
    1460              38 :     if ( eType != wkbNone )
    1461                 :     {
    1462                 :         /* Declare our feature type */
    1463              36 :         CPLCreateXMLElementAndValue(defn_xml,"FeatureType", "esriFTSimple");
    1464              36 :         CPLCreateXMLElementAndValue(defn_xml,"ShapeType", esri_type.c_str());
    1465              36 :         CPLCreateXMLElementAndValue(defn_xml,"ShapeFieldName", geometry_name.c_str());
    1466                 : 
    1467                 :         /* Dimensionality */
    1468              36 :         CPLCreateXMLElementAndValue(defn_xml,"HasM", "false");
    1469              36 :         CPLCreateXMLElementAndValue(defn_xml,"HasZ", (has_z ? "true" : "false"));
    1470                 : 
    1471                 :         /* TODO: Handle spatial indexes (layer creation option?) */
    1472              36 :         CPLCreateXMLElementAndValue(defn_xml,"HasSpatialIndex", "false");
    1473                 : 
    1474                 :         /* These field are required for Arcmap to display aliases correctly */
    1475              36 :         CPLCreateXMLNode(defn_xml, CXT_Element, "AreaFieldName");
    1476              36 :         CPLCreateXMLNode(defn_xml, CXT_Element, "LengthFieldName");
    1477                 : 
    1478                 :         /* We can't know the extent at this point <Extent xsi:nil='true'/> */
    1479              36 :         CPLXMLNode *extn_xml = CPLCreateXMLNode(defn_xml, CXT_Element, "Extent");
    1480              36 :         FGDB_CPLAddXMLAttribute(extn_xml, "xsi:nil", "true");
    1481                 :     }
    1482                 : 
    1483                 :     /* Feature Class with known SRS gets an SRS entry */
    1484              38 :     if( eType != wkbNone && srs_xml != NULL)
    1485                 :     {
    1486              36 :         CPLAddXMLChild(defn_xml, CPLCloneXMLTree(srs_xml));
    1487                 :     }
    1488                 : 
    1489                 :     /* Convert our XML tree into a string for FGDB */
    1490                 :     char *defn_str;
    1491                 :     
    1492              38 :     if( CSLFetchNameValue( papszOptions, "XML_DEFINITION") != NULL )
    1493               1 :         defn_str = CPLStrdup(CSLFetchNameValue( papszOptions, "XML_DEFINITION"));
    1494                 :     else
    1495              37 :         defn_str = CPLSerializeXMLTree(xml_xml);
    1496              38 :     CPLDestroyXMLNode(xml_xml);
    1497                 : 
    1498                 :     /* TODO, tie this to debugging levels */
    1499              38 :     CPLDebug("FGDB", "%s", defn_str);
    1500                 :     //std::cout << defn_str << std::endl;
    1501                 : 
    1502                 :     /* Create the table. */
    1503              38 :     Table *table = new Table;
    1504              76 :     Geodatabase *gdb = pParentDataSource->GetGDB();
    1505              38 :     fgdbError hr = gdb->CreateTable(defn_str, wparent_path, *table);
    1506                 :     
    1507                 :     /* Free the XML */
    1508              38 :     CPLFree(defn_str);
    1509                 : 
    1510                 :     /* Check table create status */
    1511              38 :     if (FAILED(hr))
    1512                 :     {
    1513               3 :         delete table;
    1514               3 :         return GDBErr(hr, "Failed at creating table for " + table_path);
    1515                 :     }
    1516                 : 
    1517                 :     /* Store the new FGDB Table pointer and set up the OGRFeatureDefn */
    1518              35 :     return FGdbLayer::Initialize(pParentDataSource, table, wtable_path, L"Table");
    1519                 : }
    1520                 : 
    1521                 : /*************************************************************************/
    1522                 : /*                            Initialize()                               */
    1523                 : /* Has ownership of the table as soon as it is called.                   */
    1524                 : /************************************************************************/
    1525                 : 
    1526             182 : bool FGdbLayer::Initialize(FGdbDataSource* pParentDataSource, Table* pTable,
    1527                 :                            std::wstring wstrTablePath, std::wstring wstrType)
    1528                 : {
    1529                 :     long hr;
    1530                 : 
    1531             182 :     m_pDS = pParentDataSource; // we never assume ownership of the parent - so our destructor should not delete
    1532                 : 
    1533             182 :     m_pTable = pTable;
    1534                 : 
    1535             182 :     m_wstrTablePath = wstrTablePath;
    1536             182 :     m_wstrType = wstrType;
    1537                 : 
    1538             182 :     wstring wstrQueryName;
    1539             182 :     if (FAILED(hr = pParentDataSource->GetGDB()->GetQueryName(wstrTablePath, wstrQueryName)))
    1540                 :         return GDBErr(hr, "Failed at getting underlying table name for " +
    1541               0 :                       WStringToString(wstrTablePath));
    1542                 : 
    1543             182 :     m_strName = WStringToString(wstrQueryName);
    1544                 : 
    1545             182 :     m_pFeatureDefn = new OGRFeatureDefn(m_strName.c_str()); //TODO: Should I "new" an OGR smart pointer - sample says so, but it doesn't seem right
    1546                 :     //as long as we use the same compiler & settings in both the ogr build and this
    1547                 :     //driver, we should be OK
    1548             182 :     m_pFeatureDefn->Reference();
    1549                 : 
    1550             182 :     string tableDef;
    1551             182 :     if (FAILED(hr = m_pTable->GetDefinition(tableDef)))
    1552                 :         return GDBErr(hr, "Failed at getting table definition for " +
    1553               0 :                       WStringToString(wstrTablePath));
    1554                 : 
    1555                 :     //xxx  printf("Table definition = %s", tableDef.c_str() );
    1556                 : 
    1557             182 :     bool abort = false;
    1558                 : 
    1559                 :     // extract schema information from table
    1560             182 :     CPLXMLNode *psRoot = CPLParseXMLString( tableDef.c_str() );
    1561                 : 
    1562             182 :     if (psRoot == NULL)
    1563                 :     {
    1564                 :         CPLError( CE_Failure, CPLE_AppDefined, "%s",
    1565               0 :                   ("Failed parsing GDB Table Schema XML for " + m_strName).c_str());
    1566               0 :         return false;
    1567                 :     }
    1568                 : 
    1569             182 :     CPLXMLNode *pDataElementNode = psRoot->psNext; // Move to next field which should be DataElement
    1570                 : 
    1571             182 :     if( pDataElementNode != NULL
    1572                 :         && pDataElementNode->psChild != NULL
    1573                 :         && pDataElementNode->eType == CXT_Element
    1574                 :         && EQUAL(pDataElementNode->pszValue,"esri:DataElement") )
    1575                 :     {
    1576                 :         CPLXMLNode *psNode;
    1577                 : 
    1578            4986 :         for( psNode = pDataElementNode->psChild;
    1579                 :         psNode != NULL;
    1580                 :         psNode = psNode->psNext )
    1581                 :         {
    1582            4804 :             if( psNode->eType == CXT_Element && psNode->psChild != NULL )
    1583                 :             {
    1584            3554 :                 if (EQUAL(psNode->pszValue,"OIDFieldName") )
    1585                 :                 {
    1586                 :                     char* pszUnescaped = CPLUnescapeString(
    1587             182 :                     psNode->psChild->pszValue, NULL, CPLES_XML);
    1588             182 :                     m_strOIDFieldName = pszUnescaped;
    1589             182 :                     CPLFree(pszUnescaped);
    1590                 :                 }
    1591            3372 :                 else if (EQUAL(psNode->pszValue,"ShapeFieldName") )
    1592                 :                 {
    1593                 :                     char* pszUnescaped = CPLUnescapeString(
    1594             170 :                     psNode->psChild->pszValue, NULL, CPLES_XML);
    1595             170 :                     m_strShapeFieldName = pszUnescaped;
    1596             170 :                     CPLFree(pszUnescaped);
    1597                 :                 }
    1598            3202 :                 else if (EQUAL(psNode->pszValue,"Fields") )
    1599                 :                 {
    1600             182 :                     if (!GDBToOGRFields(psNode))
    1601                 :                     {
    1602               0 :                         abort = true;
    1603               0 :                         break;
    1604                 :                     }
    1605                 :                 }
    1606                 :             }
    1607                 :         }
    1608                 : 
    1609             182 :         if (m_strShapeFieldName.size() == 0)
    1610              12 :             m_pFeatureDefn->SetGeomType(wkbNone);
    1611                 :     }
    1612                 :     else
    1613                 :     {
    1614                 :         CPLError( CE_Failure, CPLE_AppDefined, "%s",
    1615               0 :                 ("Failed parsing GDB Table Schema XML (DataElement) for " + m_strName).c_str());
    1616               0 :         return false;
    1617                 :     }
    1618             182 :     CPLDestroyXMLNode( psRoot );
    1619                 : 
    1620             182 :     if (abort)
    1621               0 :         return false;
    1622                 : 
    1623             182 :     return true; //AOToOGRFields(ipFields, m_pFeatureDefn, m_vOGRFieldToESRIField);
    1624                 : }
    1625                 : 
    1626                 : /************************************************************************/
    1627                 : /*                          ParseGeometryDef()                          */
    1628                 : /************************************************************************/
    1629                 : 
    1630             170 : bool FGdbLayer::ParseGeometryDef(CPLXMLNode* psRoot)
    1631                 : {
    1632                 :     CPLXMLNode *psGeometryDefItem;
    1633                 : 
    1634             170 :     string geometryType;
    1635             170 :     bool hasZ = false;
    1636             170 :     string wkt, wkid;
    1637                 : 
    1638            1360 :     for (psGeometryDefItem = psRoot->psChild;
    1639                 :         psGeometryDefItem != NULL;
    1640                 :         psGeometryDefItem = psGeometryDefItem->psNext )
    1641                 :     {
    1642                 :         //loop through all "GeometryDef" elements
    1643                 :         //
    1644                 : 
    1645            1190 :         if (psGeometryDefItem->eType == CXT_Element &&
    1646                 :             psGeometryDefItem->psChild != NULL)
    1647                 :         {
    1648            1020 :             if (EQUAL(psGeometryDefItem->pszValue,"GeometryType"))
    1649                 :             {
    1650                 :                 char* pszUnescaped = CPLUnescapeString(
    1651             170 :                     psGeometryDefItem->psChild->pszValue, NULL, CPLES_XML);
    1652                 : 
    1653             170 :                 geometryType = pszUnescaped;
    1654                 : 
    1655             170 :                 CPLFree(pszUnescaped);
    1656                 :             }
    1657             850 :             else if (EQUAL(psGeometryDefItem->pszValue,"SpatialReference"))
    1658                 :             {
    1659             170 :                 ParseSpatialReference(psGeometryDefItem, &wkt, &wkid); // we don't check for success because it
    1660                 :                                                                 // may not be there
    1661                 :             }
    1662                 :             /* No M support in OGR yet
    1663                 :             else if (EQUAL(psFieldNode->pszValue,"HasM")
    1664                 :             {
    1665                 :                 char* pszUnescaped = CPLUnescapeString(psNode->psChild->pszValue, NULL, CPLES_XML);
    1666                 : 
    1667                 :                 if (!strcmp(szUnescaped, "true"))
    1668                 :                 hasM = true;
    1669                 : 
    1670                 :                 CPLFree(pszUnescaped);
    1671                 :             }
    1672                 :             */
    1673             680 :             else if (EQUAL(psGeometryDefItem->pszValue,"HasZ"))
    1674                 :             {
    1675                 :                 char* pszUnescaped = CPLUnescapeString(
    1676             170 :                     psGeometryDefItem->psChild->pszValue, NULL, CPLES_XML);
    1677                 : 
    1678             170 :                 if (!strcmp(pszUnescaped, "true"))
    1679              60 :                 hasZ = true;
    1680                 : 
    1681             170 :                 CPLFree(pszUnescaped);
    1682                 :             }
    1683                 :         }
    1684                 : 
    1685                 :     }
    1686                 : 
    1687                 :     OGRwkbGeometryType ogrGeoType;
    1688             170 :     if (!GDBToOGRGeometry(geometryType, hasZ, &ogrGeoType))
    1689               0 :         return false;
    1690                 : 
    1691             170 :     m_pFeatureDefn->SetGeomType(ogrGeoType);
    1692                 : 
    1693             170 :     if (wkbFlatten(ogrGeoType) == wkbMultiLineString ||
    1694                 :         wkbFlatten(ogrGeoType) == wkbMultiPoint)
    1695              60 :         m_forceMulti = true;
    1696                 : 
    1697             170 :     if (wkid.length() > 0)
    1698                 :     {
    1699             166 :         m_pSRS = new OGRSpatialReference();
    1700             332 :         if (m_pSRS->importFromEPSG(atoi(wkid.c_str())) != OGRERR_NONE)
    1701                 :         {
    1702               0 :             delete m_pSRS;
    1703               0 :             m_pSRS = NULL;
    1704                 :         }
    1705                 :         else
    1706             166 :             return true;
    1707                 :     }
    1708                 : 
    1709               4 :     if (wkt.length() > 0)
    1710                 :     {
    1711               0 :         if (!GDBToOGRSpatialReference(wkt, &m_pSRS))
    1712                 :         {
    1713                 :             //report error, but be passive about it
    1714                 :             CPLError( CE_Warning, CPLE_AppDefined,
    1715               0 :                       "Failed Mapping ESRI Spatial Reference");
    1716                 :         }
    1717                 :     }
    1718                 :     else
    1719                 :     {
    1720                 :         //report error, but be passive about it
    1721               4 :         CPLError( CE_Warning, CPLE_AppDefined, "Empty Spatial Reference");
    1722                 :     }
    1723                 : 
    1724               4 :     return true;
    1725                 : }
    1726                 : 
    1727                 : /************************************************************************/
    1728                 : /*                        ParseSpatialReference()                       */
    1729                 : /************************************************************************/
    1730                 : 
    1731             170 : bool FGdbLayer::ParseSpatialReference(CPLXMLNode* psSpatialRefNode,
    1732                 :                                       string* pOutWkt, string* pOutWKID)
    1733                 : {
    1734             170 :     *pOutWkt = "";
    1735             170 :     *pOutWKID = "";
    1736                 : 
    1737                 :     CPLXMLNode* psSRItemNode;
    1738                 : 
    1739                 :     /* Loop through all the SRS elements we want to store */
    1740            2032 :     for( psSRItemNode = psSpatialRefNode->psChild;
    1741                 :          psSRItemNode != NULL;
    1742                 :          psSRItemNode = psSRItemNode->psNext )
    1743                 :     {
    1744                 :         /* The WKID maps (mostly) to an EPSG code */
    1745            2028 :         if( psSRItemNode->eType == CXT_Element &&
    1746                 :             psSRItemNode->psChild != NULL &&
    1747                 :             EQUAL(psSRItemNode->pszValue,"WKID") )
    1748                 :         {
    1749             166 :             char* pszUnescaped = CPLUnescapeString(psSRItemNode->psChild->pszValue, NULL, CPLES_XML);
    1750             166 :             *pOutWKID = pszUnescaped;
    1751             166 :             CPLFree(pszUnescaped);
    1752                 :         }
    1753                 :         /* The WKT well-known text can be converted by OGR */
    1754            1696 :         else if( psSRItemNode->eType == CXT_Element &&
    1755                 :                 psSRItemNode->psChild != NULL &&
    1756                 :                 EQUAL(psSRItemNode->pszValue,"WKT") )
    1757                 :         {
    1758             166 :             char* pszUnescaped = CPLUnescapeString(psSRItemNode->psChild->pszValue, NULL, CPLES_XML);
    1759             166 :             *pOutWkt = pszUnescaped;
    1760             166 :             CPLFree(pszUnescaped);
    1761                 :         }
    1762                 : 
    1763                 :     }
    1764             170 :     return (*pOutWkt != "" || *pOutWKID != "");
    1765                 : }
    1766                 : 
    1767                 : /************************************************************************/
    1768                 : /*                          GDBToOGRFields()                           */
    1769                 : /************************************************************************/
    1770                 : 
    1771             182 : bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
    1772                 : {
    1773             182 :     m_vOGRFieldToESRIField.clear();
    1774                 : 
    1775             182 :     if (psRoot->psChild == NULL || psRoot->psChild->psNext == NULL)
    1776                 :     {
    1777               0 :         CPLError( CE_Failure, CPLE_AppDefined, "Unrecognized GDB XML Schema");
    1778                 : 
    1779               0 :         return false;
    1780                 :     }
    1781                 : 
    1782             182 :     psRoot = psRoot->psChild->psNext; //change root to "FieldArray"
    1783                 : 
    1784                 :     //CPLAssert(ogrToESRIFieldMapping.size() == pOGRFeatureDef->GetFieldCount());
    1785                 : 
    1786                 :     CPLXMLNode* psFieldNode;
    1787                 : 
    1788            1284 :     for( psFieldNode = psRoot->psChild;
    1789                 :         psFieldNode != NULL;
    1790                 :         psFieldNode = psFieldNode->psNext )
    1791                 :     {
    1792                 :         //loop through all "Field" elements
    1793                 :         //
    1794                 : 
    1795            1102 :         if( psFieldNode->eType == CXT_Element && psFieldNode->psChild != NULL &&
    1796                 :             EQUAL(psFieldNode->pszValue,"Field"))
    1797                 :         {
    1798                 : 
    1799                 :             CPLXMLNode* psFieldItemNode;
    1800             920 :             std::string fieldName;
    1801             920 :             std::string fieldType;
    1802             920 :             int nLength = 0;
    1803             920 :             int nPrecision = 0;
    1804                 : 
    1805                 :             // loop through all items in Field element
    1806                 :             //
    1807                 : 
    1808            9908 :             for( psFieldItemNode = psFieldNode->psChild;
    1809                 :                 psFieldItemNode != NULL;
    1810                 :                 psFieldItemNode = psFieldItemNode->psNext )
    1811                 :             {
    1812            8988 :                 if (psFieldItemNode->eType == CXT_Element)
    1813                 :                 {
    1814                 : 
    1815            8068 :                 if (EQUAL(psFieldItemNode->pszValue,"Name"))
    1816                 :                 {
    1817                 :                     char* pszUnescaped = CPLUnescapeString(
    1818             920 :                         psFieldItemNode->psChild->pszValue, NULL, CPLES_XML);
    1819             920 :                     fieldName = pszUnescaped;
    1820             920 :                     CPLFree(pszUnescaped);
    1821                 :                 }
    1822            7148 :                 else if (EQUAL(psFieldItemNode->pszValue,"Type") )
    1823                 :                 {
    1824                 :                     char* pszUnescaped = CPLUnescapeString(
    1825             920 :                         psFieldItemNode->psChild->pszValue, NULL, CPLES_XML);
    1826             920 :                     fieldType = pszUnescaped;
    1827             920 :                     CPLFree(pszUnescaped);
    1828                 :                 }
    1829            6228 :                 else if (EQUAL(psFieldItemNode->pszValue,"GeometryDef") )
    1830                 :                 {
    1831             170 :                     if (!ParseGeometryDef(psFieldItemNode))
    1832               0 :                         return false; // if we failed parsing the GeometryDef, we are done!
    1833                 :                 }
    1834            6058 :                 else if (EQUAL(psFieldItemNode->pszValue,"Length") )
    1835                 :                 {
    1836             920 :                     nLength = atoi(psFieldItemNode->psChild->pszValue);
    1837                 :                 }
    1838            5138 :                 else if (EQUAL(psFieldItemNode->pszValue,"Precision") )
    1839                 :                 {
    1840             920 :                     nPrecision = atoi(psFieldItemNode->psChild->pszValue);
    1841                 :                 }
    1842                 :                 }
    1843                 :             }
    1844                 : 
    1845                 : 
    1846                 :             ///////////////////////////////////////////////////////////////////
    1847                 :             // At this point we have parsed everything about the current field
    1848                 : 
    1849                 : 
    1850             920 :             if (fieldType == "esriFieldTypeGeometry")
    1851                 :             {
    1852             170 :                 m_strShapeFieldName = fieldName;
    1853                 : 
    1854             170 :                 continue; // finish here for special field - don't add as OGR fielddef
    1855                 :             }
    1856             750 :             else if (fieldType == "esriFieldTypeOID")
    1857                 :             {
    1858                 :                 //m_strOIDFieldName = fieldName; // already set by this point
    1859                 : 
    1860             182 :                 continue; // finish here for special field - don't add as OGR fielddef
    1861                 :             }
    1862                 : 
    1863                 :             OGRFieldType ogrType;
    1864                 :             //CPLDebug("FGDB", "name = %s, type = %s", fieldName.c_str(), fieldType.c_str() );
    1865             568 :             if (!GDBToOGRFieldType(fieldType, &ogrType))
    1866                 :             {
    1867                 :                 // field cannot be mapped, skipping further processing
    1868                 :                 CPLError( CE_Warning, CPLE_AppDefined, "Skipping field: [%s] type: [%s] ",
    1869               0 :                 fieldName.c_str(), fieldType.c_str() );
    1870               0 :                 continue;
    1871                 :             }
    1872                 : 
    1873                 : 
    1874                 :             //TODO: Optimization - modify m_wstrSubFields so it only fetches fields that are mapped
    1875                 : 
    1876             568 :             OGRFieldDefn fieldTemplate( fieldName.c_str(), ogrType);
    1877                 :             //fieldTemplate.SetWidth(nLength);
    1878                 :             //fieldTemplate.SetPrecision(nPrecision);
    1879             568 :             m_pFeatureDefn->AddFieldDefn( &fieldTemplate );
    1880                 : 
    1881             568 :             m_vOGRFieldToESRIField.push_back(StringToWString(fieldName));
    1882             568 :             m_vOGRFieldToESRIFieldType.push_back( fieldType );
    1883                 : 
    1884                 :         }
    1885                 :     }
    1886                 : 
    1887             182 :     return true;
    1888                 : }
    1889                 : 
    1890                 : 
    1891                 : /************************************************************************/
    1892                 : /*                            ResetReading()                            */
    1893                 : /************************************************************************/
    1894                 : 
    1895             419 : void FGdbLayer::ResetReading()
    1896                 : {
    1897                 :     long hr;
    1898                 : 
    1899             419 :     EndBulkLoad();
    1900                 : 
    1901             419 :     if (m_pOGRFilterGeometry && !m_pOGRFilterGeometry->IsEmpty())
    1902                 :     {
    1903                 :         // Search spatial
    1904                 :         // As of beta1, FileGDB only supports bbox searched, if we have GEOS installed,
    1905                 :         // we can do the rest ourselves.
    1906                 : 
    1907              78 :         OGREnvelope ogrEnv;
    1908                 : 
    1909              78 :         m_pOGRFilterGeometry->getEnvelope(&ogrEnv);
    1910                 : 
    1911                 :         //spatial query
    1912              78 :         FileGDBAPI::Envelope env(ogrEnv.MinX, ogrEnv.MaxX, ogrEnv.MinY, ogrEnv.MaxY);
    1913                 : 
    1914              78 :         if FAILED(hr = m_pTable->Search(m_wstrSubfields, m_wstrWhereClause, env, true, *m_pEnumRows))
    1915               0 :         GDBErr(hr, "Failed Searching");
    1916                 : 
    1917              78 :         m_bFilterDirty = false;
    1918                 : 
    1919              78 :         return;
    1920                 :     }
    1921                 : 
    1922                 :     // Search non-spatial
    1923                 : 
    1924             341 :     if FAILED(hr = m_pTable->Search(m_wstrSubfields, m_wstrWhereClause, true, *m_pEnumRows))
    1925               0 :         GDBErr(hr, "Failed Searching");
    1926                 : 
    1927             341 :     m_bFilterDirty = false;
    1928                 :   
    1929                 : }
    1930                 : 
    1931                 : /************************************************************************/
    1932                 : /*                         SetSpatialFilter()                           */
    1933                 : /************************************************************************/
    1934                 : 
    1935             183 : void FGdbLayer::SetSpatialFilter( OGRGeometry* pOGRGeom )
    1936                 : {
    1937             183 :     if (m_pOGRFilterGeometry)
    1938                 :     {
    1939              26 :         OGRGeometryFactory::destroyGeometry(m_pOGRFilterGeometry);
    1940              26 :         m_pOGRFilterGeometry = NULL;
    1941                 :     }
    1942                 : 
    1943             183 :     if (pOGRGeom == NULL || pOGRGeom->IsEmpty())
    1944                 :     {
    1945             157 :         m_bFilterDirty = true;
    1946                 : 
    1947             157 :         return;
    1948                 :     }
    1949                 : 
    1950              26 :     m_pOGRFilterGeometry = pOGRGeom->clone();
    1951                 : 
    1952              26 :     m_pOGRFilterGeometry->transformTo(m_pSRS);
    1953                 : 
    1954              26 :     m_bFilterDirty = true;
    1955                 : }
    1956                 : 
    1957                 : /************************************************************************/
    1958                 : /*                         SetSpatialFilterRect()                       */
    1959                 : /************************************************************************/
    1960                 : 
    1961               0 : void FGdbLayer::SetSpatialFilterRect (double dfMinX, double dfMinY, double dfMaxX, double dfMaxY)
    1962                 : {
    1963                 : 
    1964                 :     //TODO: can optimize this by changing how the filter gets generated -
    1965                 :     //this will work for now
    1966                 : 
    1967               0 :     OGRGeometry* pTemp = OGRGeometryFactory::createGeometry(wkbPolygon);
    1968                 : 
    1969               0 :     pTemp->assignSpatialReference(m_pSRS);
    1970                 : 
    1971               0 :     OGRLinearRing ring;
    1972                 : 
    1973               0 :     ring.addPoint( dfMinX, dfMinY );
    1974               0 :     ring.addPoint( dfMinX, dfMaxY );
    1975               0 :     ring.addPoint( dfMaxX, dfMaxY );
    1976               0 :     ring.addPoint( dfMaxX, dfMinY );
    1977               0 :     ring.addPoint( dfMinX, dfMinY );
    1978               0 :     ((OGRPolygon *) pTemp)->addRing( &ring );
    1979                 : 
    1980               0 :     SetSpatialFilter(pTemp);
    1981                 : 
    1982               0 :     OGRGeometryFactory::destroyGeometry(pTemp);
    1983               0 : }
    1984                 : 
    1985                 : 
    1986                 : /************************************************************************/
    1987                 : /*                         SetAttributeFilter()                         */
    1988                 : /************************************************************************/
    1989                 : 
    1990             144 : OGRErr FGdbLayer::SetAttributeFilter( const char* pszQuery )
    1991                 : {
    1992             144 :     m_wstrWhereClause = StringToWString( (pszQuery != NULL) ? pszQuery : "" );
    1993                 : 
    1994             144 :     m_bFilterDirty = true;
    1995                 : 
    1996             144 :     return OGRERR_NONE;
    1997                 : }
    1998                 : 
    1999                 : /************************************************************************/
    2000                 : /*                           OGRFeatureFromGdbRow()                      */
    2001                 : /************************************************************************/
    2002                 : 
    2003             959 : bool FGdbBaseLayer::OGRFeatureFromGdbRow(Row* pRow, OGRFeature** ppFeature)
    2004                 : {
    2005                 :     long hr;
    2006                 : 
    2007             959 :     OGRFeature* pOutFeature = new OGRFeature(m_pFeatureDefn);
    2008                 : 
    2009                 :     /////////////////////////////////////////////////////////
    2010                 :     // Translate OID
    2011                 :     //
    2012                 : 
    2013             959 :     int32 oid = -1;
    2014             959 :     if (FAILED(hr = pRow->GetOID(oid)))
    2015                 :     {
    2016                 :         //this should never happen
    2017               0 :         delete pOutFeature;
    2018               0 :         return false;
    2019                 :     }
    2020             959 :     pOutFeature->SetFID(oid);
    2021                 : 
    2022                 : 
    2023                 :     /////////////////////////////////////////////////////////
    2024                 :     // Translate Geometry
    2025                 :     //
    2026                 : 
    2027             959 :     ShapeBuffer gdbGeometry;
    2028                 :     // Row::GetGeometry() will fail with -2147467259 for NULL geometries
    2029                 :     // Row::GetGeometry() will fail with -2147219885 for tables without a geometry field
    2030             959 :     if (!FAILED(hr = pRow->GetGeometry(gdbGeometry)))
    2031                 :     {
    2032             801 :         OGRGeometry* pOGRGeo = NULL;
    2033                 : 
    2034             801 :         if ((!GDBGeometryToOGRGeometry(m_forceMulti, &gdbGeometry, m_pSRS, &pOGRGeo)) || pOGRGeo == NULL)
    2035                 :         {
    2036               0 :             delete pOutFeature;
    2037               0 :             return GDBErr(hr, "Failed to translate FileGDB Geometry to OGR Geometry for row " + string(CPLSPrintf("%d", (int)oid)));
    2038                 :         }
    2039                 : 
    2040             801 :         pOutFeature->SetGeometryDirectly(pOGRGeo);
    2041                 :     }
    2042                 : 
    2043                 : 
    2044                 :     //////////////////////////////////////////////////////////
    2045                 :     // Map fields
    2046                 :     //
    2047                 : 
    2048                 : 
    2049             959 :     size_t mappedFieldCount = m_vOGRFieldToESRIField.size();
    2050                 : 
    2051             959 :     bool foundBadColumn = false;
    2052                 : 
    2053            4697 :     for (size_t i = 0; i < mappedFieldCount; ++i)
    2054                 :     {
    2055            3738 :         const wstring & wstrFieldName = m_vOGRFieldToESRIField[i];
    2056            3738 :         const std::string & strFieldType = m_vOGRFieldToESRIFieldType[i];
    2057                 : 
    2058            3738 :         bool isNull = false;
    2059                 : 
    2060            3738 :         if (FAILED(hr = pRow->IsNull(wstrFieldName, isNull)))
    2061                 :         {
    2062                 :             GDBErr(hr, "Failed to determine NULL status from column " +
    2063               0 :                    WStringToString(wstrFieldName));
    2064               0 :             foundBadColumn = true;
    2065               0 :             continue;
    2066                 :         }
    2067                 : 
    2068            3738 :         if (isNull)
    2069                 :         {
    2070              40 :             continue; //leave as unset
    2071                 :         }
    2072                 : 
    2073                 :         //
    2074                 :         // NOTE: This switch statement needs to be kept in sync with GDBToOGRFieldType utility function
    2075                 :         //       since we are only checking for types we mapped in that utility function
    2076                 : 
    2077            3698 :         switch (m_pFeatureDefn->GetFieldDefn(i)->GetType())
    2078                 :         {
    2079                 : 
    2080                 :             case OFTInteger:
    2081                 :             {
    2082                 :                 int32 val;
    2083                 : 
    2084            1717 :                 if (FAILED(hr = pRow->GetInteger(wstrFieldName, val)))
    2085                 :                 {
    2086                 :                     int16 shortval;
    2087               1 :                     if (FAILED(hr = pRow->GetShort(wstrFieldName, shortval)))
    2088                 :                     {
    2089                 :                         GDBErr(hr, "Failed to determine integer value for column " +
    2090               0 :                                WStringToString(wstrFieldName));
    2091               0 :                         foundBadColumn = true;
    2092               0 :                         continue;
    2093                 :                     }
    2094               1 :                     val = shortval;
    2095                 :                 }
    2096                 : 
    2097            1717 :                 pOutFeature->SetField(i, (int)val);
    2098                 :             }
    2099            1717 :             break;
    2100                 : 
    2101                 :             case OFTReal:
    2102                 :             {
    2103            1059 :                 if (strFieldType == "esriFieldTypeSingle")
    2104                 :                 {
    2105                 :                     float val;
    2106                 : 
    2107               1 :                     if (FAILED(hr = pRow->GetFloat(wstrFieldName, val)))
    2108                 :                     {
    2109                 :                         GDBErr(hr, "Failed to determine float value for column " +
    2110               0 :                                WStringToString(wstrFieldName));
    2111               0 :                         foundBadColumn = true;
    2112               0 :                         continue;
    2113                 :                     }
    2114                 : 
    2115               1 :                     pOutFeature->SetField(i, val);
    2116                 :                 }
    2117                 :                 else
    2118                 :                 {
    2119                 :                     double val;
    2120                 : 
    2121            1058 :                     if (FAILED(hr = pRow->GetDouble(wstrFieldName, val)))
    2122                 :                     {
    2123                 :                         GDBErr(hr, "Failed to determine real value for column " +
    2124               0 :                                WStringToString(wstrFieldName));
    2125               0 :                         foundBadColumn = true;
    2126               0 :                         continue;
    2127                 :                     }
    2128                 : 
    2129            1058 :                     pOutFeature->SetField(i, val);
    2130                 :                 }
    2131                 :             }
    2132            1059 :             break;
    2133                 :             case OFTString:
    2134                 :             {
    2135             921 :                 wstring val;
    2136                 :                 
    2137             921 :                 if( strFieldType == "esriFieldTypeGlobalID" )
    2138                 :                 {
    2139               1 :                     Guid guid;
    2140               1 :                     if( FAILED(hr = pRow->GetGlobalID(guid)) ||
    2141                 :                         FAILED(hr = guid.ToString(val)) )
    2142                 :                     {
    2143                 :                         GDBErr(hr, "Failed to determine string value for column " +
    2144               0 :                             WStringToString(wstrFieldName));
    2145               0 :                         foundBadColumn = true;
    2146               0 :                         continue;
    2147               0 :                     }
    2148                 :                 }
    2149             920 :                 else if( strFieldType == "esriFieldTypeGUID" )
    2150                 :                 {
    2151               1 :                     Guid guid;
    2152               1 :                     if( FAILED(hr = pRow->GetGUID(wstrFieldName, guid)) ||
    2153                 :                         FAILED(hr = guid.ToString(val)) )
    2154                 :                     {
    2155                 :                         GDBErr(hr, "Failed to determine string value for column " +
    2156               0 :                             WStringToString(wstrFieldName));
    2157               0 :                         foundBadColumn = true;
    2158               0 :                         continue;
    2159               0 :                     }
    2160                 :                 }
    2161                 :                 else
    2162                 :                 {
    2163             919 :                     if (FAILED(hr = pRow->GetString(wstrFieldName, val)))
    2164                 :                     {
    2165                 :                         GDBErr(hr, "Failed to determine string value for column " +
    2166               0 :                             WStringToString(wstrFieldName));
    2167               0 :                         foundBadColumn = true;
    2168               0 :                         continue;
    2169                 :                     }
    2170                 :                 }
    2171                 : 
    2172             921 :                 pOutFeature->SetField(i, WStringToString(val).c_str());
    2173                 :             }
    2174             921 :             break;
    2175                 : 
    2176                 :             /* TODO: Need to get test dataset to implement these leave it as NULL for now
    2177                 :             case OFTBinary:
    2178                 :             {
    2179                 :                 ByteArray binaryBuf;
    2180                 : 
    2181                 :                 if (FAILED(hr = pRow->GetBinary(wstrFieldName, binaryBuf)))
    2182                 :                 {
    2183                 :                 GDBErr(hr, "Failed to determine binary value for column " + WStringToString(wstrFieldName));
    2184                 :                 foundBadColumn = true;
    2185                 :                 continue;
    2186                 :                 }
    2187                 : 
    2188                 :                 pOutFeature->SetField(i, (int)binaryBuf.inUseLength, (GByte*)binaryBuf.byteArray);
    2189                 :             }
    2190                 :             break;
    2191                 :             */
    2192                 : 
    2193                 :             case OFTDateTime:
    2194                 :             {
    2195                 :                 struct tm val;
    2196                 : 
    2197               1 :                 if (FAILED(hr = pRow->GetDate(wstrFieldName, val)))
    2198                 :                 {
    2199                 :                     GDBErr(hr, "Failed to determine date value for column " +
    2200               0 :                            WStringToString(wstrFieldName));
    2201               0 :                     foundBadColumn = true;
    2202               0 :                     continue;
    2203                 :                 }
    2204                 : 
    2205                 :                 pOutFeature->SetField(i, val.tm_year + 1900, val.tm_mon + 1,
    2206               1 :                                       val.tm_mday, val.tm_hour, val.tm_min, val.tm_sec);
    2207                 :             // Examine test data to figure out how to extract that
    2208                 :             }
    2209               1 :             break;
    2210                 : 
    2211                 :             default:
    2212                 :             {
    2213               0 :                 if (!m_supressColumnMappingError)
    2214                 :                 {
    2215               0 :                     foundBadColumn = true;
    2216                 :                     CPLError( CE_Warning, CPLE_AppDefined,
    2217                 :                             "Row id: %d col:%d has unhandled col type (%d). Setting to NULL.",
    2218               0 :                             (int)oid, (int)i, m_pFeatureDefn->GetFieldDefn(i)->GetType());
    2219                 :                 }
    2220                 :             }
    2221                 :         }
    2222                 :     }
    2223                 : 
    2224             959 :     if (foundBadColumn)
    2225               0 :         m_supressColumnMappingError = true;
    2226                 : 
    2227                 : 
    2228             959 :     *ppFeature = pOutFeature;
    2229                 : 
    2230             959 :     return true;
    2231                 : }
    2232                 : 
    2233                 : 
    2234                 : /************************************************************************/
    2235                 : /*                           GetNextFeature()                           */
    2236                 : /************************************************************************/
    2237                 : 
    2238            1060 : OGRFeature* FGdbLayer::GetNextFeature()
    2239                 : {
    2240            1060 :     if (m_bFilterDirty)
    2241              21 :         ResetReading();
    2242                 : 
    2243            1060 :     EndBulkLoad();
    2244                 : 
    2245            1060 :     return FGdbBaseLayer::GetNextFeature();
    2246                 : }
    2247                 : 
    2248                 : /************************************************************************/
    2249                 : /*                             GetFeature()                             */
    2250                 : /************************************************************************/
    2251                 : 
    2252             112 : OGRFeature *FGdbLayer::GetFeature( long oid )
    2253                 : {
    2254                 :     // do query to fetch individual row
    2255             112 :     EnumRows       enumRows;
    2256             112 :     Row            row;
    2257                 : 
    2258             112 :     EndBulkLoad();
    2259                 : 
    2260             112 :     if (GetRow(enumRows, row, oid) != OGRERR_NONE)
    2261              48 :         return NULL;
    2262                 : 
    2263              64 :     OGRFeature* pOGRFeature = NULL;
    2264                 : 
    2265              64 :     if (!OGRFeatureFromGdbRow(&row,  &pOGRFeature))
    2266                 :     {
    2267               0 :         return NULL;
    2268                 :     }
    2269                 : 
    2270              64 :     return pOGRFeature;
    2271                 : }
    2272                 : 
    2273                 : 
    2274                 : /************************************************************************/
    2275                 : /*                          GetFeatureCount()                           */
    2276                 : /************************************************************************/
    2277                 : 
    2278             204 : int FGdbLayer::GetFeatureCount( int bForce )
    2279                 : {
    2280                 :     long           hr;
    2281             204 :     int32          rowCount = 0;
    2282                 : 
    2283             204 :     EndBulkLoad();
    2284                 : 
    2285             204 :     if (m_pOGRFilterGeometry != NULL || m_wstrWhereClause.size() != 0)
    2286              58 :         return OGRLayer::GetFeatureCount(bForce);
    2287                 : 
    2288             146 :     if (FAILED(hr = m_pTable->GetRowCount(rowCount)))
    2289                 :     {
    2290               0 :         GDBErr(hr, "Failed counting rows");
    2291               0 :         return 0;
    2292                 :     }
    2293                 : 
    2294                 : #if 0
    2295                 :   Row            row;
    2296                 :   EnumRows       enumRows;
    2297                 : 
    2298                 :   if (FAILED(hr = m_pTable->Search(StringToWString(m_strOIDFieldName), L"", true, enumRows)))
    2299                 :   {
    2300                 :     GDBErr(hr, "Failed counting rows");
    2301                 :     return -1;
    2302                 :   }
    2303                 : 
    2304                 :   while (S_OK == (hr = enumRows.Next(row)))
    2305                 :     ++rowCount;
    2306                 : 
    2307                 :   if (FAILED(hr))
    2308                 :   {
    2309                 :     GDBErr(hr, "Failed counting rows (during fetch)");
    2310                 :     return -1;
    2311                 :   }
    2312                 : #endif
    2313                 : 
    2314             146 :     return static_cast<int>(rowCount);
    2315                 : }
    2316                 : 
    2317                 : 
    2318                 : 
    2319                 : /************************************************************************/
    2320                 : /*                             GetExtent()                              */
    2321                 : /************************************************************************/
    2322                 : 
    2323              30 : OGRErr FGdbLayer::GetExtent (OGREnvelope* psExtent, int bForce)
    2324                 : {
    2325              30 :     if (m_pOGRFilterGeometry != NULL || m_wstrWhereClause.size() != 0 ||
    2326                 :         m_strShapeFieldName.size() == 0)
    2327               1 :         return OGRLayer::GetExtent(psExtent, bForce);
    2328                 : 
    2329                 :     long hr;
    2330              29 :     Envelope envelope;
    2331              29 :     if (FAILED(hr = m_pTable->GetExtent(envelope)))
    2332                 :     {
    2333               0 :         GDBErr(hr, "Failed fetching extent");
    2334               0 :         return OGRERR_FAILURE;
    2335                 :     }
    2336                 : 
    2337              29 :     psExtent->MinX = envelope.xMin;
    2338              29 :     psExtent->MinY = envelope.yMin;
    2339              29 :     psExtent->MaxX = envelope.xMax;
    2340              29 :     psExtent->MaxY = envelope.yMax;
    2341                 : 
    2342              29 :     if (CPLIsNan(psExtent->MinX) ||
    2343                 :         CPLIsNan(psExtent->MinY) ||
    2344                 :         CPLIsNan(psExtent->MaxX) ||
    2345                 :         CPLIsNan(psExtent->MaxY))
    2346               2 :         return OGRERR_FAILURE;
    2347                 : 
    2348              27 :     return OGRERR_NONE;
    2349                 : }
    2350                 : 
    2351                 : /************************************************************************/
    2352                 : /*                          StartBulkLoad()                             */
    2353                 : /************************************************************************/
    2354                 : 
    2355               1 : void FGdbLayer::StartBulkLoad ()
    2356                 : {
    2357               1 :     if ( ! m_pTable )
    2358               0 :         return;
    2359                 : 
    2360               1 :     if ( m_bBulkLoadInProgress )
    2361               0 :         return;
    2362                 : 
    2363               1 :     m_bBulkLoadInProgress = TRUE;
    2364               1 :     m_pTable->LoadOnlyMode(true);
    2365               1 :     m_pTable->SetWriteLock();
    2366                 : }
    2367                 : 
    2368                 : /************************************************************************/
    2369                 : /*                           EndBulkLoad()                              */
    2370                 : /************************************************************************/
    2371                 : 
    2372            2061 : void FGdbLayer::EndBulkLoad ()
    2373                 : {
    2374            2061 :     if ( ! m_pTable )
    2375               3 :         return;
    2376                 : 
    2377            2058 :     if ( ! m_bBulkLoadInProgress )
    2378            2057 :         return;
    2379                 : 
    2380               1 :     m_bBulkLoadInProgress = FALSE;
    2381               1 :     m_bBulkLoadAllowed = -1; /* so that the configuration option is read the first time we CreateFeature() again */
    2382               1 :     m_pTable->LoadOnlyMode(false);
    2383               1 :     m_pTable->FreeWriteLock();
    2384                 : }
    2385                 : 
    2386                 : /* OGRErr FGdbLayer::StartTransaction ()
    2387                 : {
    2388                 :     if ( ! m_pTable ) 
    2389                 :         return OGRERR_FAILURE;
    2390                 :         
    2391                 :     m_pTable->LoadOnlyMode(true);
    2392                 :     m_pTable->SetWriteLock();
    2393                 :     return OGRERR_NONE;
    2394                 :     
    2395                 : } */
    2396                 : 
    2397                 : 
    2398                 : /* OGRErr FGdbLayer::CommitTransaction ()
    2399                 : {
    2400                 :     if ( ! m_pTable ) 
    2401                 :         return OGRERR_FAILURE;
    2402                 :     
    2403                 :     m_pTable->LoadOnlyMode(false);
    2404                 :     m_pTable->FreeWriteLock();
    2405                 :     return OGRERR_NONE;
    2406                 : } */
    2407                 : 
    2408                 : /* OGRErr FGdbLayer::RollbackTransaction ()
    2409                 : {
    2410                 :     if ( ! m_pTable ) 
    2411                 :         return OGRERR_FAILURE;
    2412                 :     
    2413                 :     m_pTable->LoadOnlyMode(false);
    2414                 :     m_pTable->FreeWriteLock();
    2415                 :     return OGRERR_NONE;
    2416                 : } */
    2417                 : 
    2418                 : 
    2419                 : /************************************************************************/
    2420                 : /*                           GetLayerXML()                              */
    2421                 : /* Return XML definition of the Layer as provided by FGDB. Caller must  */
    2422                 : /* free result.                                                         */
    2423                 : /* Not currently used by the driver, but can be used by external code   */
    2424                 : /* for specific purposes.                                               */
    2425                 : /************************************************************************/
    2426                 : 
    2427              15 : OGRErr FGdbLayer::GetLayerXML (char **ppXml)
    2428                 : {
    2429                 :     long hr;
    2430              15 :     std::string xml;
    2431                 : 
    2432              15 :     if ( FAILED(hr = m_pTable->GetDefinition(xml)) )
    2433                 :     {
    2434               0 :         GDBErr(hr, "Failed fetching XML table definition");
    2435               0 :         return OGRERR_FAILURE;
    2436                 :     }
    2437                 : 
    2438              15 :     *ppXml = CPLStrdup(xml.c_str());
    2439              15 :     return OGRERR_NONE;
    2440                 : }
    2441                 : 
    2442                 : /************************************************************************/
    2443                 : /*                           GetLayerMetadataXML()                      */
    2444                 : /* Return XML metadata for the Layer as provided by FGDB. Caller must  */
    2445                 : /* free result.                                                         */
    2446                 : /* Not currently used by the driver, but can be used by external code   */
    2447                 : /* for specific purposes.                                               */
    2448                 : /************************************************************************/
    2449                 : 
    2450              15 : OGRErr FGdbLayer::GetLayerMetadataXML (char **ppXml)
    2451                 : {
    2452                 :     long hr;
    2453              15 :     std::string xml;
    2454                 : 
    2455              15 :     if ( FAILED(hr = m_pTable->GetDocumentation(xml)) )
    2456                 :     {
    2457               0 :         GDBErr(hr, "Failed fetching XML table metadata");
    2458               0 :         return OGRERR_FAILURE;
    2459                 :     }
    2460                 : 
    2461              15 :     *ppXml = CPLStrdup(xml.c_str());
    2462              15 :     return OGRERR_NONE;
    2463                 : }
    2464                 : 
    2465                 : /************************************************************************/
    2466                 : /*                           TestCapability()                           */
    2467                 : /************************************************************************/
    2468                 : 
    2469             192 : int FGdbLayer::TestCapability( const char* pszCap )
    2470                 : {
    2471                 : 
    2472             192 :     if (EQUAL(pszCap,OLCRandomRead))
    2473              48 :         return TRUE;
    2474                 : 
    2475             144 :     else if (EQUAL(pszCap,OLCFastFeatureCount)) 
    2476               0 :         return m_pOGRFilterGeometry == NULL && m_wstrWhereClause.size() == 0;
    2477                 : 
    2478             144 :     else if (EQUAL(pszCap,OLCFastSpatialFilter))
    2479               0 :         return TRUE;
    2480                 : 
    2481             144 :     else if (EQUAL(pszCap,OLCFastGetExtent))
    2482               0 :         return m_pOGRFilterGeometry == NULL && m_wstrWhereClause.size() == 0;
    2483                 : 
    2484             144 :     else if (EQUAL(pszCap,OLCCreateField)) /* CreateField() */
    2485               0 :         return TRUE;
    2486                 : 
    2487             144 :     else if (EQUAL(pszCap,OLCSequentialWrite)) /* CreateFeature() */
    2488              16 :         return TRUE;
    2489                 : 
    2490             128 :     else if (EQUAL(pszCap,OLCStringsAsUTF8)) /* Native UTF16, converted to UTF8 */
    2491              16 :         return TRUE;
    2492                 : 
    2493             112 :     else if (EQUAL(pszCap,OLCReorderFields)) /* TBD ReorderFields() */
    2494               0 :         return FALSE;
    2495                 : 
    2496             112 :     else if (EQUAL(pszCap,OLCDeleteFeature)) /* DeleteFeature() */
    2497              16 :         return TRUE;
    2498                 : 
    2499              96 :     else if (EQUAL(pszCap,OLCRandomWrite)) /* SetFeature() */
    2500              16 :         return TRUE;
    2501                 : 
    2502              80 :     else if (EQUAL(pszCap,OLCDeleteField)) /* DeleteField() */
    2503               0 :         return TRUE;
    2504                 : 
    2505                 : #ifdef AlterFieldDefn_implemented_but_not_working
    2506                 :     else if (EQUAL(pszCap,OLCAlterFieldDefn)) /* AlterFieldDefn() */
    2507                 :         return TRUE;
    2508                 : #endif
    2509                 : 
    2510              80 :     else if (EQUAL(pszCap,OLCFastSetNextByIndex)) /* TBD FastSetNextByIndex() */
    2511              16 :         return FALSE;
    2512                 : 
    2513              64 :     else if (EQUAL(pszCap,OLCTransactions)) /* TBD Start/End Transactions() */
    2514              32 :         return FALSE;
    2515                 :         
    2516                 :     else 
    2517              32 :         return FALSE;
    2518            2139 : }

Generated by: LCOV version 1.7