1 : /**********************************************************************
2 : * $Id: mitab_ogr_datasource.cpp,v 1.12 2007/03/22 20:01:36 dmorissette Exp $
3 : *
4 : * Name: mitab_ogr_datasource.cpp
5 : * Project: MapInfo Mid/Mif, Tab ogr support
6 : * Language: C++
7 : * Purpose: Implementation of OGRTABDataSource.
8 : * Author: Stephane Villeneuve, stephane.v@videotron.ca
9 : * and Frank Warmerdam, warmerdam@pobox.com
10 : *
11 : **********************************************************************
12 : * Copyright (c) 1999, 2000, Stephane Villeneuve
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining a
15 : * copy of this software and associated documentation files (the "Software"),
16 : * to deal in the Software without restriction, including without limitation
17 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 : * and/or sell copies of the Software, and to permit persons to whom the
19 : * Software is furnished to do so, subject to the following conditions:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
24 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 : * DEALINGS IN THE SOFTWARE.
31 : **********************************************************************
32 : *
33 : * $Log: mitab_ogr_datasource.cpp,v $
34 : * Revision 1.12 2007/03/22 20:01:36 dmorissette
35 : * Added SPATIAL_INDEX_MODE=QUICK creation option (MITAB bug 1669)
36 : *
37 : * Revision 1.11 2006/01/27 14:27:35 fwarmerdam
38 : * fixed ogr bounds setting problems (bug 1198)
39 : *
40 : * Revision 1.10 2005/09/20 04:40:02 fwarmerdam
41 : * fixed CPLReadDir memory leak
42 : *
43 : * Revision 1.9 2004/10/15 01:52:30 fwarmerdam
44 : * Modified CreateLayer() to use -1000,-1000,1000,1000 bounds for GEOGCS
45 : * much like in mitab_bounds.cpp. This ensures that geographic files in
46 : * the range 0-360 works as well as -180 to 180.
47 : *
48 : * Revision 1.8 2004/07/07 15:42:46 fwarmerdam
49 : * fixed up some single layer creation issues
50 : *
51 : * Revision 1.7 2004/02/27 21:06:03 fwarmerdam
52 : * Better support for "single file" creation ... don't allow other layers to
53 : * be created. But *do* single file to satisfy the first layer creation request
54 : * made. Also, allow creating a datasource "on" an existing directory.
55 : *
56 : * Revision 1.6 2003/03/21 14:20:49 warmerda
57 : * fixed email
58 : *
59 : * Revision 1.5 2002/02/08 16:52:16 warmerda
60 : * added support for FORMAT=MIF option for creating layers
61 : *
62 : * Revision 1.4 2001/02/06 22:13:54 warmerda
63 : * fixed memory leak in OGRTABDataSource::CreateLayer()
64 : *
65 : * Revision 1.3 2001/01/22 16:03:58 warmerda
66 : * expanded tabs
67 : *
68 : * Revision 1.2 2000/07/04 01:46:23 warmerda
69 : * Avoid warnings on unused arguments.
70 : *
71 : * Revision 1.1 2000/01/26 18:17:09 warmerda
72 : * New
73 : *
74 : **********************************************************************/
75 :
76 : #include "mitab_ogr_driver.h"
77 :
78 :
79 : /*=======================================================================
80 : * OGRTABDataSource
81 : *
82 : * We need one single OGRDataSource/Driver set of classes to handle all
83 : * the MapInfo file types. They all deal with the IMapInfoFile abstract
84 : * class.
85 : *=====================================================================*/
86 :
87 : /************************************************************************/
88 : /* OGRTABDataSource() */
89 : /************************************************************************/
90 :
91 197 : OGRTABDataSource::OGRTABDataSource()
92 :
93 : {
94 197 : m_pszName = NULL;
95 197 : m_pszDirectory = NULL;
96 197 : m_nLayerCount = 0;
97 197 : m_papoLayers = NULL;
98 197 : m_papszOptions = NULL;
99 197 : m_bCreateMIF = FALSE;
100 197 : m_bSingleFile = FALSE;
101 197 : m_bSingleLayerAlreadyCreated = FALSE;
102 197 : m_bQuickSpatialIndexMode = FALSE;
103 197 : }
104 :
105 : /************************************************************************/
106 : /* ~OGRTABDataSource() */
107 : /************************************************************************/
108 :
109 197 : OGRTABDataSource::~OGRTABDataSource()
110 :
111 : {
112 197 : CPLFree( m_pszName );
113 197 : CPLFree( m_pszDirectory );
114 :
115 219 : for( int i = 0; i < m_nLayerCount; i++ )
116 22 : delete m_papoLayers[i];
117 :
118 197 : CPLFree( m_papoLayers );
119 197 : CSLDestroy( m_papszOptions );
120 197 : }
121 :
122 : /************************************************************************/
123 : /* Create() */
124 : /* */
125 : /* Create a new dataset (directory or file). */
126 : /************************************************************************/
127 :
128 9 : int OGRTABDataSource::Create( const char * pszName, char **papszOptions )
129 :
130 : {
131 : VSIStatBuf sStat;
132 : const char *pszOpt;
133 :
134 9 : CPLAssert( m_pszName == NULL );
135 :
136 9 : m_pszName = CPLStrdup( pszName );
137 9 : m_papszOptions = CSLDuplicate( papszOptions );
138 :
139 9 : if( (pszOpt=CSLFetchNameValue(papszOptions,"FORMAT")) != NULL
140 : && EQUAL(pszOpt, "MIF") )
141 1 : m_bCreateMIF = TRUE;
142 8 : else if( EQUAL(CPLGetExtension(pszName),"mif")
143 : || EQUAL(CPLGetExtension(pszName),"mid") )
144 6 : m_bCreateMIF = TRUE;
145 :
146 9 : if( (pszOpt=CSLFetchNameValue(papszOptions,"SPATIAL_INDEX_MODE")) != NULL
147 : && EQUAL(pszOpt, "QUICK") )
148 0 : m_bQuickSpatialIndexMode = TRUE;
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* Create a new empty directory. */
152 : /* -------------------------------------------------------------------- */
153 9 : if( strlen(CPLGetExtension(pszName)) == 0 )
154 : {
155 2 : if( VSIStat( pszName, &sStat ) == 0 )
156 : {
157 2 : if( !VSI_ISDIR(sStat.st_mode) )
158 : {
159 : CPLError( CE_Failure, CPLE_OpenFailed,
160 : "Attempt to create dataset named %s,\n"
161 : "but that is an existing file.\n",
162 0 : pszName );
163 0 : return FALSE;
164 : }
165 : }
166 : else
167 : {
168 0 : if( VSIMkdir( pszName, 0755 ) != 0 )
169 : {
170 : CPLError( CE_Failure, CPLE_AppDefined,
171 : "Unable to create directory %s.\n",
172 0 : pszName );
173 0 : return FALSE;
174 : }
175 : }
176 :
177 2 : m_pszDirectory = CPLStrdup(pszName);
178 : }
179 :
180 : /* -------------------------------------------------------------------- */
181 : /* Create a new single file. */
182 : /* -------------------------------------------------------------------- */
183 : else
184 : {
185 : IMapInfoFile *poFile;
186 :
187 7 : if( m_bCreateMIF )
188 6 : poFile = new MIFFile;
189 : else
190 1 : poFile = new TABFile;
191 :
192 7 : if( poFile->Open( pszName, "wb", FALSE ) != 0 )
193 : {
194 0 : delete poFile;
195 0 : return FALSE;
196 : }
197 :
198 7 : m_nLayerCount = 1;
199 7 : m_papoLayers = (IMapInfoFile **) CPLMalloc(sizeof(void*));
200 7 : m_papoLayers[0] = poFile;
201 :
202 7 : m_pszDirectory = CPLStrdup( CPLGetPath(pszName) );
203 7 : m_bSingleFile = TRUE;
204 : }
205 :
206 9 : return TRUE;
207 : }
208 :
209 : /************************************************************************/
210 : /* Open() */
211 : /* */
212 : /* Open an existing file, or directory of files. */
213 : /************************************************************************/
214 :
215 188 : int OGRTABDataSource::Open( const char * pszName, int bTestOpen )
216 :
217 : {
218 : VSIStatBuf stat;
219 :
220 188 : CPLAssert( m_pszName == NULL );
221 :
222 188 : m_pszName = CPLStrdup( pszName );
223 :
224 : /* -------------------------------------------------------------------- */
225 : /* Is this a file or directory? */
226 : /* -------------------------------------------------------------------- */
227 188 : if( VSIStat( pszName, &stat ) != 0
228 : || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
229 : {
230 18 : if( !bTestOpen )
231 : {
232 : CPLError( CE_Failure, CPLE_OpenFailed,
233 : "%s is not a file or directory.\n"
234 : "Unable to open as a Mapinfo dataset.\n",
235 0 : pszName );
236 : }
237 :
238 18 : return FALSE;
239 : }
240 :
241 : /* -------------------------------------------------------------------- */
242 : /* If it is a file, try to open as a Mapinfo file. */
243 : /* -------------------------------------------------------------------- */
244 170 : if( VSI_ISREG(stat.st_mode) )
245 : {
246 : IMapInfoFile *poFile;
247 :
248 165 : poFile = IMapInfoFile::SmartOpen( pszName, bTestOpen );
249 165 : if( poFile == NULL )
250 154 : return FALSE;
251 :
252 11 : m_nLayerCount = 1;
253 11 : m_papoLayers = (IMapInfoFile **) CPLMalloc(sizeof(void*));
254 11 : m_papoLayers[0] = poFile;
255 :
256 11 : m_pszDirectory = CPLStrdup( CPLGetPath(pszName) );
257 : }
258 :
259 : /* -------------------------------------------------------------------- */
260 : /* Otherwise, we need to scan the whole directory for files */
261 : /* ending in .tab or .mif. */
262 : /* -------------------------------------------------------------------- */
263 : else
264 : {
265 5 : char **papszFileList = CPLReadDir( pszName );
266 :
267 5 : m_pszDirectory = CPLStrdup( pszName );
268 :
269 56 : for( int iFile = 0;
270 : papszFileList != NULL && papszFileList[iFile] != NULL;
271 : iFile++ )
272 : {
273 : IMapInfoFile *poFile;
274 51 : const char *pszExtension = CPLGetExtension(papszFileList[iFile]);
275 : char *pszSubFilename;
276 :
277 51 : if( !EQUAL(pszExtension,"tab") && !EQUAL(pszExtension,"mif") )
278 49 : continue;
279 :
280 : pszSubFilename = CPLStrdup(
281 2 : CPLFormFilename( m_pszDirectory, papszFileList[iFile], NULL ));
282 :
283 2 : poFile = IMapInfoFile::SmartOpen( pszSubFilename, bTestOpen );
284 2 : CPLFree( pszSubFilename );
285 :
286 2 : if( poFile == NULL )
287 : {
288 0 : CSLDestroy( papszFileList );
289 0 : return FALSE;
290 : }
291 :
292 2 : m_nLayerCount++;
293 : m_papoLayers = (IMapInfoFile **)
294 2 : CPLRealloc(m_papoLayers,sizeof(void*)*m_nLayerCount);
295 2 : m_papoLayers[m_nLayerCount-1] = poFile;
296 : }
297 :
298 5 : CSLDestroy( papszFileList );
299 :
300 5 : if( m_nLayerCount == 0 )
301 : {
302 3 : if( !bTestOpen )
303 : CPLError( CE_Failure, CPLE_OpenFailed,
304 : "No mapinfo files found in directory %s.\n",
305 0 : m_pszDirectory );
306 :
307 3 : return FALSE;
308 : }
309 : }
310 :
311 13 : return TRUE;
312 : }
313 :
314 : /************************************************************************/
315 : /* GetLayerCount() */
316 : /************************************************************************/
317 :
318 59 : int OGRTABDataSource::GetLayerCount()
319 :
320 : {
321 59 : if( m_bSingleFile && !m_bSingleLayerAlreadyCreated )
322 4 : return 0;
323 : else
324 55 : return m_nLayerCount;
325 : }
326 :
327 : /************************************************************************/
328 : /* GetLayer() */
329 : /************************************************************************/
330 :
331 33 : OGRLayer *OGRTABDataSource::GetLayer( int iLayer )
332 :
333 : {
334 33 : if( iLayer < 0 || iLayer >= GetLayerCount() )
335 0 : return NULL;
336 : else
337 33 : return m_papoLayers[iLayer];
338 : }
339 :
340 : /************************************************************************/
341 : /* CreateLayer() */
342 : /************************************************************************/
343 :
344 : OGRLayer *
345 : OGRTABDataSource::CreateLayer( const char * pszLayerName,
346 : OGRSpatialReference *poSRSIn,
347 : OGRwkbGeometryType /* eGeomTypeIn */,
348 9 : char ** /* papszOptions */ )
349 :
350 : {
351 : IMapInfoFile *poFile;
352 : char *pszFullFilename;
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* If it's a single file mode file, then we may have already */
356 : /* instantiated the low level layer. We would just need to */
357 : /* reset the coordinate system and (potentially) bounds. */
358 : /* -------------------------------------------------------------------- */
359 9 : if( m_bSingleFile )
360 : {
361 7 : if( m_bSingleLayerAlreadyCreated )
362 : {
363 : CPLError( CE_Failure, CPLE_AppDefined,
364 0 : "Unable to create new layers in this single file dataset.");
365 0 : return NULL;
366 : }
367 :
368 7 : m_bSingleLayerAlreadyCreated = TRUE;
369 :
370 7 : poFile = (IMapInfoFile *) m_papoLayers[0];
371 : }
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* We need to initially create the file, and add it as a layer. */
375 : /* -------------------------------------------------------------------- */
376 : else
377 : {
378 2 : if( m_bCreateMIF )
379 : {
380 : pszFullFilename = CPLStrdup( CPLFormFilename( m_pszDirectory,
381 1 : pszLayerName, "mif" ) );
382 :
383 1 : poFile = new MIFFile;
384 : }
385 : else
386 : {
387 : pszFullFilename = CPLStrdup( CPLFormFilename( m_pszDirectory,
388 1 : pszLayerName, "tab" ) );
389 :
390 1 : poFile = new TABFile;
391 : }
392 :
393 2 : if( poFile->Open( pszFullFilename, "wb", FALSE ) != 0 )
394 : {
395 0 : CPLFree( pszFullFilename );
396 0 : delete poFile;
397 0 : return FALSE;
398 : }
399 :
400 2 : m_nLayerCount++;
401 : m_papoLayers = (IMapInfoFile **)
402 2 : CPLRealloc(m_papoLayers,sizeof(void*)*m_nLayerCount);
403 2 : m_papoLayers[m_nLayerCount-1] = poFile;
404 :
405 2 : CPLFree( pszFullFilename );
406 : }
407 :
408 : /* -------------------------------------------------------------------- */
409 : /* Assign the coordinate system (if provided) and set */
410 : /* reasonable bounds. */
411 : /* -------------------------------------------------------------------- */
412 9 : if( poSRSIn != NULL )
413 1 : poFile->SetSpatialRef( poSRSIn );
414 :
415 9 : if( !poFile->IsBoundsSet() && !m_bCreateMIF )
416 : {
417 1 : if( poSRSIn != NULL && poSRSIn->GetRoot() != NULL
418 : && EQUAL(poSRSIn->GetRoot()->GetValue(),"GEOGCS") )
419 0 : poFile->SetBounds( -1000, -1000, 1000, 1000 );
420 : else
421 1 : poFile->SetBounds( -30000000, -15000000, 30000000, 15000000 );
422 : }
423 :
424 9 : if (m_bQuickSpatialIndexMode && poFile->SetQuickSpatialIndexMode() != 0)
425 : {
426 : CPLError( CE_Warning, CPLE_AppDefined,
427 0 : "Setting Quick Spatial Index Mode failed.");
428 : }
429 :
430 9 : return poFile;
431 : }
432 :
433 : /************************************************************************/
434 : /* TestCapability() */
435 : /************************************************************************/
436 :
437 4 : int OGRTABDataSource::TestCapability( const char * pszCap )
438 :
439 : {
440 4 : if( EQUAL(pszCap,ODsCCreateLayer) )
441 4 : return !m_bSingleFile || !m_bSingleLayerAlreadyCreated;
442 : else
443 0 : return FALSE;
444 : }
445 :
|