1
/******************************************************************************
2
* $Id: FGdbDatasource.cpp 23394 2011-11-19 19:20:12Z rouault $
4
* Project: OpenGIS Simple Features Reference Implementation
5
* Purpose: Implements FileGDB OGR Datasource.
6
* Author: Ragi Yaser Burhum, ragi@burhum.com
7
* Paul Ramsey, pramsey at cleverelephant.ca
9
******************************************************************************
10
* Copyright (c) 2010, Ragi Yaser Burhum
11
* Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
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:
20
* The above copyright notice and this permission notice shall be included
21
* in all copies or substantial portions of the Software.
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
****************************************************************************/
34
#include "cpl_string.h"
36
#include "FGdbUtils.h"
38
CPL_CVSID("$Id: FGdbDatasource.cpp 23394 2011-11-19 19:20:12Z rouault $");
43
/************************************************************************/
44
/* FGdbDataSource() */
45
/************************************************************************/
47
FGdbDataSource::FGdbDataSource():
49
m_pszName(0), m_pGeodatabase(NULL)
53
/************************************************************************/
54
/* ~FGdbDataSource() */
55
/************************************************************************/
57
FGdbDataSource::~FGdbDataSource()
61
size_t count = m_layers.size();
62
for(size_t i = 0; i < count; ++i )
67
::CloseGeodatabase(*m_pGeodatabase);
68
delete m_pGeodatabase;
73
/************************************************************************/
75
/************************************************************************/
77
int FGdbDataSource::Open(Geodatabase* pGeodatabase, const char * pszNewName, int bUpdate )
79
m_pszName = CPLStrdup( pszNewName );
80
m_pGeodatabase = pGeodatabase;
82
std::vector<std::wstring> typesRequested;
84
// We're only interested in Tables, Feature Datasets and Feature Classes
85
typesRequested.push_back(L"Feature Class");
86
typesRequested.push_back(L"Table");
87
typesRequested.push_back(L"Feature Dataset");
89
bool rv = LoadLayers(L"\\");
94
/************************************************************************/
95
/* OpenFGDBTables() */
96
/************************************************************************/
98
bool FGdbDataSource::OpenFGDBTables(const std::wstring &type,
99
const std::vector<std::wstring> &layers)
102
for ( unsigned int i = 0; i < layers.size(); i++ )
104
Table* pTable = new Table;
105
//CPLDebug("FGDB", "Opening %s", WStringToString(layers[i]).c_str());
106
if (FAILED(hr = m_pGeodatabase->OpenTable(layers[i], *pTable)))
109
GDBDebug(hr, "Error opening " + WStringToString(layers[i]) + ". Skipping it");
112
FGdbLayer* pLayer = new FGdbLayer;
113
if (!pLayer->Initialize(this, pTable, layers[i], type))
116
return GDBErr(hr, "Error initializing OGRLayer for " + WStringToString(layers[i]));
119
m_layers.push_back(pLayer);
124
/************************************************************************/
126
/************************************************************************/
128
bool FGdbDataSource::LoadLayers(const std::wstring &root)
130
std::vector<wstring> tables;
131
std::vector<wstring> featureclasses;
132
std::vector<wstring> featuredatasets;
135
/* Find all the Tables in the root */
136
if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Table", tables)) )
138
return GDBErr(hr, "Error reading Tables in " + WStringToString(root));
140
/* Open the tables we found */
141
if ( tables.size() > 0 && ! OpenFGDBTables(L"Table", tables) )
144
/* Find all the Feature Classes in the root */
145
if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Class", featureclasses)) )
147
return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(root));
149
/* Open the tables we found */
150
if ( featureclasses.size() > 0 && ! OpenFGDBTables(L"Feature Class", featureclasses) )
153
/* Find all the Feature Datasets in the root */
154
if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Dataset", featuredatasets)) )
156
return GDBErr(hr, "Error reading Feature Datasets in " + WStringToString(root));
158
/* Look for Feature Classes inside the Feature Dataset */
159
for ( unsigned int i = 0; i < featuredatasets.size(); i++ )
161
if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(featuredatasets[i], L"Feature Class", featureclasses)) )
163
return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(featuredatasets[i]));
165
if ( featureclasses.size() > 0 && ! OpenFGDBTables(L"Feature Class", featureclasses) )
173
/************************************************************************/
174
/* LoadLayersOld() */
175
/************************************************************************/
177
/* Old recursive LoadLayers. Removed in favor of simple one that only
178
looks at FeatureClasses and Tables. */
180
// Flattens out hierarchichal GDB structure
181
bool FGdbDataSource::LoadLayersOld(const std::vector<wstring> & datasetTypes,
182
const wstring & parent)
186
// I didn't find an API to give me the type of the dataset based on name - I am *not*
187
// parsing XML for something like this - in the meantime I can use this hack to see
188
// if the dataset had any children whatsoever - if so, then I won't attempt to open it
189
// otherwise, do attempt to do that
191
bool childrenFound = false;
192
bool errorsEncountered = false;
194
for (size_t dsTypeIndex = 0; dsTypeIndex < datasetTypes.size(); dsTypeIndex++)
196
std::vector<wstring> childDatasets;
197
m_pGeodatabase->GetChildDatasets( parent, datasetTypes[dsTypeIndex], childDatasets);
199
if (childDatasets.size() > 0)
201
//it is a container of other datasets
203
for (size_t childDatasetIndex = 0;
204
childDatasetIndex < childDatasets.size();
207
childrenFound = true;
209
// do something with it
210
// For now, we just ignore dataset containers and only open the children
211
//std::wcout << datasetTypes[dsTypeIndex] << L" " << childDatasets[childDatasetIndex] << std::endl;
213
if (!LoadLayersOld(datasetTypes, childDatasets[childDatasetIndex]))
214
errorsEncountered = true;
219
//it is a full fledged dataset itself without children - open it (except the root)
221
if ((!childrenFound) && parent != L"\\")
223
//wcout << "Opening " << parent << "...";
224
Table* pTable = new Table;
225
if (FAILED(hr = m_pGeodatabase->OpenTable(parent,*pTable)))
228
return GDBErr(hr, "Error opening " + WStringToString(parent));
231
FGdbLayer* pLayer = new FGdbLayer;
233
//pLayer has ownership of the table pointer as soon Initialize is called
234
if (!pLayer->Initialize(this, pTable, parent))
238
return GDBErr(hr, "Error initializing OGRLayer for " +
239
WStringToString(parent));
242
m_layers.push_back(pLayer);
245
return !errorsEncountered;
250
/************************************************************************/
252
/************************************************************************/
254
OGRErr FGdbDataSource::DeleteLayer( int iLayer )
256
if( iLayer < 0 || iLayer >= static_cast<int>(m_layers.size()) )
257
return OGRERR_FAILURE;
259
// Fetch FGDBAPI Table before deleting OGR layer object
261
Table* pTable = m_layers[iLayer]->GetTable();
263
std::string name = m_layers[iLayer]->GetLayerDefn()->GetName();
264
std::wstring strPath = m_layers[iLayer]->GetTablePath();
265
std::wstring strType = m_layers[iLayer]->GetType();
268
delete m_layers[iLayer];
270
pTable = NULL; // OGR Layer had ownership of FGDB Table
272
m_layers.erase(m_layers.begin() + iLayer);
276
if (FAILED(hr = m_pGeodatabase->Delete(strPath, strType)))
278
CPLError( CE_Warning, CPLE_AppDefined,
279
"%s was not deleted however it has been closed", name.c_str());
280
GDBErr(hr, "Failed deleting dataset");
281
return OGRERR_FAILURE;
287
/************************************************************************/
288
/* TestCapability() */
289
/************************************************************************/
291
int FGdbDataSource::TestCapability( const char * pszCap )
293
if( EQUAL(pszCap,ODsCCreateLayer) )
296
else if( EQUAL(pszCap,ODsCDeleteLayer) )
303
/************************************************************************/
305
/************************************************************************/
307
OGRLayer *FGdbDataSource::GetLayer( int iLayer )
309
int count = static_cast<int>(m_layers.size());
311
if( iLayer < 0 || iLayer >= count )
314
return m_layers[iLayer];
317
/************************************************************************/
320
/* See FGdbLayer::Create for creation options */
321
/************************************************************************/
324
FGdbDataSource::CreateLayer( const char * pszLayerName,
325
OGRSpatialReference *poSRS,
326
OGRwkbGeometryType eType,
327
char ** papszOptions )
329
FGdbLayer* pLayer = new FGdbLayer;
330
if (!pLayer->Create(this, pszLayerName, poSRS, eType, papszOptions))
336
m_layers.push_back(pLayer);