1 : /******************************************************************************
2 : * $Id: FGdbDatasource.cpp 23394 2011-11-19 19:20:12Z rouault $
3 : *
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
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 "cpl_conv.h"
34 : #include "cpl_string.h"
35 : #include "gdal.h"
36 : #include "FGdbUtils.h"
37 :
38 : CPL_CVSID("$Id: FGdbDatasource.cpp 23394 2011-11-19 19:20:12Z rouault $");
39 :
40 : using std::vector;
41 : using std::wstring;
42 :
43 : /************************************************************************/
44 : /* FGdbDataSource() */
45 : /************************************************************************/
46 :
47 10 : FGdbDataSource::FGdbDataSource():
48 : OGRDataSource(),
49 10 : m_pszName(0), m_pGeodatabase(NULL)
50 : {
51 10 : }
52 :
53 : /************************************************************************/
54 : /* ~FGdbDataSource() */
55 : /************************************************************************/
56 :
57 10 : FGdbDataSource::~FGdbDataSource()
58 : {
59 10 : CPLFree( m_pszName );
60 :
61 10 : size_t count = m_layers.size();
62 89 : for(size_t i = 0; i < count; ++i )
63 79 : delete m_layers[i];
64 :
65 10 : if (m_pGeodatabase)
66 : {
67 10 : ::CloseGeodatabase(*m_pGeodatabase);
68 10 : delete m_pGeodatabase;
69 : }
70 10 : }
71 :
72 :
73 : /************************************************************************/
74 : /* Open() */
75 : /************************************************************************/
76 :
77 10 : int FGdbDataSource::Open(Geodatabase* pGeodatabase, const char * pszNewName, int bUpdate )
78 : {
79 10 : m_pszName = CPLStrdup( pszNewName );
80 10 : m_pGeodatabase = pGeodatabase;
81 :
82 10 : std::vector<std::wstring> typesRequested;
83 :
84 : // We're only interested in Tables, Feature Datasets and Feature Classes
85 10 : typesRequested.push_back(L"Feature Class");
86 20 : typesRequested.push_back(L"Table");
87 20 : typesRequested.push_back(L"Feature Dataset");
88 :
89 20 : bool rv = LoadLayers(L"\\");
90 :
91 10 : return rv;
92 : }
93 :
94 : /************************************************************************/
95 : /* OpenFGDBTables() */
96 : /************************************************************************/
97 :
98 7 : bool FGdbDataSource::OpenFGDBTables(const std::wstring &type,
99 : const std::vector<std::wstring> &layers)
100 : {
101 : fgdbError hr;
102 71 : for ( unsigned int i = 0; i < layers.size(); i++ )
103 : {
104 64 : Table* pTable = new Table;
105 : //CPLDebug("FGDB", "Opening %s", WStringToString(layers[i]).c_str());
106 64 : if (FAILED(hr = m_pGeodatabase->OpenTable(layers[i], *pTable)))
107 : {
108 0 : delete pTable;
109 0 : GDBDebug(hr, "Error opening " + WStringToString(layers[i]) + ". Skipping it");
110 0 : continue;
111 : }
112 64 : FGdbLayer* pLayer = new FGdbLayer;
113 128 : if (!pLayer->Initialize(this, pTable, layers[i], type))
114 : {
115 0 : delete pLayer;
116 0 : return GDBErr(hr, "Error initializing OGRLayer for " + WStringToString(layers[i]));
117 : }
118 :
119 64 : m_layers.push_back(pLayer);
120 : }
121 7 : return true;
122 : }
123 :
124 : /************************************************************************/
125 : /* LoadLayers() */
126 : /************************************************************************/
127 :
128 10 : bool FGdbDataSource::LoadLayers(const std::wstring &root)
129 : {
130 10 : std::vector<wstring> tables;
131 10 : std::vector<wstring> featureclasses;
132 10 : std::vector<wstring> featuredatasets;
133 : fgdbError hr;
134 :
135 : /* Find all the Tables in the root */
136 10 : if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Table", tables)) )
137 : {
138 0 : return GDBErr(hr, "Error reading Tables in " + WStringToString(root));
139 : }
140 : /* Open the tables we found */
141 10 : if ( tables.size() > 0 && ! OpenFGDBTables(L"Table", tables) )
142 0 : return false;
143 :
144 : /* Find all the Feature Classes in the root */
145 10 : if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Class", featureclasses)) )
146 : {
147 0 : return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(root));
148 : }
149 : /* Open the tables we found */
150 10 : if ( featureclasses.size() > 0 && ! OpenFGDBTables(L"Feature Class", featureclasses) )
151 0 : return false;
152 :
153 : /* Find all the Feature Datasets in the root */
154 10 : if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(root, L"Feature Dataset", featuredatasets)) )
155 : {
156 0 : return GDBErr(hr, "Error reading Feature Datasets in " + WStringToString(root));
157 : }
158 : /* Look for Feature Classes inside the Feature Dataset */
159 11 : for ( unsigned int i = 0; i < featuredatasets.size(); i++ )
160 : {
161 1 : if ( FAILED(hr = m_pGeodatabase->GetChildDatasets(featuredatasets[i], L"Feature Class", featureclasses)) )
162 : {
163 0 : return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(featuredatasets[i]));
164 : }
165 1 : if ( featureclasses.size() > 0 && ! OpenFGDBTables(L"Feature Class", featureclasses) )
166 0 : return false;
167 : }
168 10 : return true;
169 : }
170 :
171 :
172 : #if 0
173 : /************************************************************************/
174 : /* LoadLayersOld() */
175 : /************************************************************************/
176 :
177 : /* Old recursive LoadLayers. Removed in favor of simple one that only
178 : looks at FeatureClasses and Tables. */
179 :
180 : // Flattens out hierarchichal GDB structure
181 : bool FGdbDataSource::LoadLayersOld(const std::vector<wstring> & datasetTypes,
182 : const wstring & parent)
183 : {
184 : long hr = S_OK;
185 :
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
190 :
191 : bool childrenFound = false;
192 : bool errorsEncountered = false;
193 :
194 : for (size_t dsTypeIndex = 0; dsTypeIndex < datasetTypes.size(); dsTypeIndex++)
195 : {
196 : std::vector<wstring> childDatasets;
197 : m_pGeodatabase->GetChildDatasets( parent, datasetTypes[dsTypeIndex], childDatasets);
198 :
199 : if (childDatasets.size() > 0)
200 : {
201 : //it is a container of other datasets
202 :
203 : for (size_t childDatasetIndex = 0;
204 : childDatasetIndex < childDatasets.size();
205 : childDatasetIndex++)
206 : {
207 : childrenFound = true;
208 :
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;
212 :
213 : if (!LoadLayersOld(datasetTypes, childDatasets[childDatasetIndex]))
214 : errorsEncountered = true;
215 : }
216 : }
217 : }
218 :
219 : //it is a full fledged dataset itself without children - open it (except the root)
220 :
221 : if ((!childrenFound) && parent != L"\\")
222 : {
223 : //wcout << "Opening " << parent << "...";
224 : Table* pTable = new Table;
225 : if (FAILED(hr = m_pGeodatabase->OpenTable(parent,*pTable)))
226 : {
227 : delete pTable;
228 : return GDBErr(hr, "Error opening " + WStringToString(parent));
229 : }
230 :
231 : FGdbLayer* pLayer = new FGdbLayer;
232 :
233 : //pLayer has ownership of the table pointer as soon Initialize is called
234 : if (!pLayer->Initialize(this, pTable, parent))
235 : {
236 : delete pLayer;
237 :
238 : return GDBErr(hr, "Error initializing OGRLayer for " +
239 : WStringToString(parent));
240 : }
241 :
242 : m_layers.push_back(pLayer);
243 : }
244 :
245 : return !errorsEncountered;
246 : }
247 : #endif
248 :
249 :
250 : /************************************************************************/
251 : /* DeleteLayer() */
252 : /************************************************************************/
253 :
254 2 : OGRErr FGdbDataSource::DeleteLayer( int iLayer )
255 : {
256 2 : if( iLayer < 0 || iLayer >= static_cast<int>(m_layers.size()) )
257 0 : return OGRERR_FAILURE;
258 :
259 : // Fetch FGDBAPI Table before deleting OGR layer object
260 :
261 2 : Table* pTable = m_layers[iLayer]->GetTable();
262 :
263 2 : std::string name = m_layers[iLayer]->GetLayerDefn()->GetName();
264 4 : std::wstring strPath = m_layers[iLayer]->GetTablePath();
265 2 : std::wstring strType = m_layers[iLayer]->GetType();
266 :
267 : // delete OGR layer
268 2 : delete m_layers[iLayer];
269 :
270 2 : pTable = NULL; // OGR Layer had ownership of FGDB Table
271 :
272 2 : m_layers.erase(m_layers.begin() + iLayer);
273 :
274 : long hr;
275 :
276 2 : if (FAILED(hr = m_pGeodatabase->Delete(strPath, strType)))
277 : {
278 : CPLError( CE_Warning, CPLE_AppDefined,
279 0 : "%s was not deleted however it has been closed", name.c_str());
280 0 : GDBErr(hr, "Failed deleting dataset");
281 0 : return OGRERR_FAILURE;
282 : }
283 :
284 2 : return OGRERR_NONE;
285 : }
286 :
287 : /************************************************************************/
288 : /* TestCapability() */
289 : /************************************************************************/
290 :
291 1 : int FGdbDataSource::TestCapability( const char * pszCap )
292 : {
293 1 : if( EQUAL(pszCap,ODsCCreateLayer) )
294 1 : return TRUE;
295 :
296 0 : else if( EQUAL(pszCap,ODsCDeleteLayer) )
297 0 : return TRUE;
298 :
299 0 : return FALSE;
300 : }
301 :
302 :
303 : /************************************************************************/
304 : /* GetLayer() */
305 : /************************************************************************/
306 :
307 404 : OGRLayer *FGdbDataSource::GetLayer( int iLayer )
308 : {
309 404 : int count = static_cast<int>(m_layers.size());
310 :
311 404 : if( iLayer < 0 || iLayer >= count )
312 0 : return NULL;
313 : else
314 404 : return m_layers[iLayer];
315 : }
316 :
317 : /************************************************************************/
318 : /* CreateLayer() */
319 : /* */
320 : /* See FGdbLayer::Create for creation options */
321 : /************************************************************************/
322 :
323 : OGRLayer *
324 17 : FGdbDataSource::CreateLayer( const char * pszLayerName,
325 : OGRSpatialReference *poSRS,
326 : OGRwkbGeometryType eType,
327 : char ** papszOptions )
328 : {
329 17 : FGdbLayer* pLayer = new FGdbLayer;
330 17 : if (!pLayer->Create(this, pszLayerName, poSRS, eType, papszOptions))
331 : {
332 0 : delete pLayer;
333 0 : return NULL;
334 : }
335 :
336 17 : m_layers.push_back(pLayer);
337 :
338 17 : return pLayer;
339 1947 : }
|