1 /**********************************************************************
2 * $Id: mitab_tabseamless.cpp,v 1.10 2010-07-07 19:00:15 aboudreault Exp $
3 *
4 * Name: mitab_tabseamless.cpp
5 * Project: MapInfo TAB Read/Write library
6 * Language: C++
7 * Purpose: Implementation of the TABSeamless class, used to handle seamless
8 * .TAB datasets.
9 * Author: Daniel Morissette, dmorissette@dmsolutions.ca
10 *
11 **********************************************************************
12 * Copyright (c) 1999-2004, Daniel Morissette
13 * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included
23 * in all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 **********************************************************************
33 *
34 * $Log: mitab_tabseamless.cpp,v $
35 * Revision 1.10 2010-07-07 19:00:15 aboudreault
36 * Cleanup Win32 Compile Warnings (GDAL bug #2930)
37 *
38 * Revision 1.9 2009-03-10 13:50:02 aboudreault
39 * Fixed Overflow of FIDs in Seamless tables (bug 2015)
40 *
41 * Revision 1.8 2009-03-04 21:22:44 dmorissette
42 * Set m_nCurFeatureId=-1 in TABSeamless::ResetReading() (bug 2017)
43 *
44 * Revision 1.7 2007-06-21 14:00:23 dmorissette
45 * Added missing cast in isspace() calls to avoid failed assertion on Windows
46 * (MITAB bug 1737, GDAL ticket 1678))
47 *
48 * Revision 1.6 2004/06/30 20:29:04 dmorissette
49 * Fixed refs to old address danmo@videotron.ca
50 *
51 * Revision 1.5 2004/03/12 16:29:05 dmorissette
52 * Fixed 2 memory leaks (bug 283)
53 *
54 * Revision 1.4 2002/06/28 18:32:37 julien
55 * Add SetSpatialFilter() in TABSeamless class (Bug 164, MapServer)
56 * Use double for comparison in Coordsys2Int() in mitab_mapheaderblock.cpp
57 *
58 * Revision 1.3 2001/09/19 14:21:36 daniel
59 * On Unix: replace '\\' in file path read from tab index with '/'
60 *
61 * Revision 1.2 2001/03/15 03:57:51 daniel
62 * Added implementation for new OGRLayer::GetExtent(), returning data MBR.
63 *
64 * Revision 1.1 2001/03/09 04:38:04 danmo
65 * Update from master - version 1.1.0
66 *
67 * Revision 1.1 2001/03/09 04:16:02 daniel
68 * Added TABSeamless for reading seamless TAB files
69 *
70 **********************************************************************/
71
72 #include "mitab.h"
73 #include "mitab_utils.h"
74
75 #include <ctype.h> /* isspace() */
76
77 /*=====================================================================
78 * class TABSeamless
79 *
80 * Support for seamless vector datasets.
81 *
82 * The current implementation has some limitations (base assumptions):
83 * - Read-only
84 * - Base tables can only be of type TABFile
85 * - Feature Ids are build using the id of the base table in the main
86 * index table (upper 32 bits) and the actual feature id of each object
87 * inside the base tables (lower 32 bits).
88 * - Only relative paths are supported for base tables names.
89 *
90 *====================================================================*/
91
92
93 /**********************************************************************
94 * TABSeamless::TABSeamless()
95 *
96 * Constructor.
97 **********************************************************************/
TABSeamless()98 TABSeamless::TABSeamless()
99 {
100 m_pszFname = NULL;
101 m_pszPath = NULL;
102 m_eAccessMode = TABRead;
103 m_poFeatureDefnRef = NULL;
104 m_poCurFeature = NULL;
105 m_nCurFeatureId = -1;
106
107 m_poIndexTable = NULL;
108 m_nTableNameField = -1;
109 m_nCurBaseTableId = -1;
110 m_poCurBaseTable = NULL;
111 m_bEOF = FALSE;
112 }
113
114 /**********************************************************************
115 * TABSeamless::~TABSeamless()
116 *
117 * Destructor.
118 **********************************************************************/
~TABSeamless()119 TABSeamless::~TABSeamless()
120 {
121 Close();
122 }
123
124
ResetReading()125 void TABSeamless::ResetReading()
126 {
127 if (m_poIndexTable)
128 OpenBaseTable(-1); // Asking for first table resets everything
129
130 // Reset m_nCurFeatureId so that next pass via GetNextFeatureId()
131 // will start from the beginning
132 m_nCurFeatureId = -1;
133 }
134
135
136 /**********************************************************************
137 * TABSeamless::Open()
138 *
139 * Open a seamless .TAB dataset and initialize the structures to be ready
140 * to read features from it.
141 *
142 * Seamless .TAB files are composed of a main .TAB file in which each
143 * feature is the MBR of a base table.
144 *
145 * Set bTestOpenNoError=TRUE to silently return -1 with no error message
146 * if the file cannot be opened. This is intended to be used in the
147 * context of a TestOpen() function. The default value is FALSE which
148 * means that an error is reported if the file cannot be opened.
149 *
150 * Returns 0 on success, -1 on error.
151 **********************************************************************/
Open(const char * pszFname,TABAccess eAccess,GBool bTestOpenNoError)152 int TABSeamless::Open(const char *pszFname, TABAccess eAccess,
153 GBool bTestOpenNoError /*= FALSE*/ )
154 {
155 char nStatus = 0;
156
157 if (m_poIndexTable)
158 {
159 CPLError(CE_Failure, CPLE_AssertionFailed,
160 "Open() failed: object already contains an open file");
161 return -1;
162 }
163
164 /*-----------------------------------------------------------------
165 * Validate access mode and call the right open method
166 *----------------------------------------------------------------*/
167 if (eAccess == TABRead)
168 {
169 m_eAccessMode = TABRead;
170 nStatus = (char)OpenForRead(pszFname, bTestOpenNoError);
171 }
172 else
173 {
174 CPLError(CE_Failure, CPLE_NotSupported,
175 "Open() failed: access mode \"%d\" not supported", eAccess);
176 return -1;
177 }
178
179 return nStatus;
180 }
181
182
183 /**********************************************************************
184 * TABSeamless::OpenForRead()
185 *
186 * Open for reading
187 *
188 * Returns 0 on success, -1 on error.
189 **********************************************************************/
OpenForRead(const char * pszFname,GBool bTestOpenNoError)190 int TABSeamless::OpenForRead(const char *pszFname,
191 GBool bTestOpenNoError /*= FALSE*/ )
192 {
193 int nFnameLen = 0;
194
195 m_eAccessMode = TABRead;
196
197 /*-----------------------------------------------------------------
198 * Read main .TAB (text) file
199 *----------------------------------------------------------------*/
200 m_pszFname = CPLStrdup(pszFname);
201
202 #ifndef _WIN32
203 /*-----------------------------------------------------------------
204 * On Unix, make sure extension uses the right cases
205 * We do it even for write access because if a file with the same
206 * extension already exists we want to overwrite it.
207 *----------------------------------------------------------------*/
208 TABAdjustFilenameExtension(m_pszFname);
209 #endif
210
211 /*-----------------------------------------------------------------
212 * Open .TAB file... since it's a small text file, we will just load
213 * it as a stringlist in memory.
214 *----------------------------------------------------------------*/
215 char **papszTABFile = TAB_CSLLoad(m_pszFname);
216 if (papszTABFile == NULL)
217 {
218 if (!bTestOpenNoError)
219 {
220 CPLError(CE_Failure, CPLE_FileIO,
221 "Failed opening %s.", m_pszFname);
222 }
223
224 CPLFree(m_pszFname);
225 CSLDestroy(papszTABFile);
226 return -1;
227 }
228
229 /*-------------------------------------------------------------
230 * Look for a metadata line with "\IsSeamless" = "TRUE".
231 * If there is no such line, then we may have a valid .TAB file,
232 * but we do not support it in this class.
233 *------------------------------------------------------------*/
234 GBool bSeamlessFound = FALSE;
235 for (int i=0; !bSeamlessFound && papszTABFile && papszTABFile[i]; i++)
236 {
237 const char *pszStr = papszTABFile[i];
238 while(*pszStr != '\0' && isspace((unsigned char)*pszStr))
239 pszStr++;
240 if (EQUALN(pszStr, "\"\\IsSeamless\" = \"TRUE\"", 21))
241 bSeamlessFound = TRUE;
242 }
243 CSLDestroy(papszTABFile);
244
245 if ( !bSeamlessFound )
246 {
247 if (!bTestOpenNoError)
248 CPLError(CE_Failure, CPLE_NotSupported,
249 "%s does not appear to be a Seamless TAB File. "
250 "This type of .TAB file cannot be read by this library.",
251 m_pszFname);
252 else
253 CPLErrorReset();
254
255 CPLFree(m_pszFname);
256
257 return -1;
258 }
259
260 /*-----------------------------------------------------------------
261 * OK, this appears to be a valid seamless TAB dataset...
262 * Extract the path component from the main .TAB filename
263 * to build the filename of the base tables
264 *----------------------------------------------------------------*/
265 m_pszPath = CPLStrdup(m_pszFname);
266 nFnameLen = strlen(m_pszPath);
267 for( ; nFnameLen > 0; nFnameLen--)
268 {
269 if (m_pszPath[nFnameLen-1] == '/' ||
270 m_pszPath[nFnameLen-1] == '\\' )
271 {
272 break;
273 }
274 m_pszPath[nFnameLen-1] = '\0';
275 }
276
277 /*-----------------------------------------------------------------
278 * Open the main Index table and look for the "Table" field that
279 * should contain the path to the base table for each rectangle MBR
280 *----------------------------------------------------------------*/
281 m_poIndexTable = new TABFile;
282 if (m_poIndexTable->Open(m_pszFname, m_eAccessMode, bTestOpenNoError) != 0)
283 {
284 // Open Failed... an error has already been reported, just return.
285 if (bTestOpenNoError)
286 CPLErrorReset();
287 Close();
288 return -1;
289 }
290
291 OGRFeatureDefn *poDefn = m_poIndexTable->GetLayerDefn();
292 if (poDefn == NULL ||
293 (m_nTableNameField = poDefn->GetFieldIndex("Table")) == -1)
294 {
295 if (!bTestOpenNoError)
296 CPLError(CE_Failure, CPLE_NotSupported,
297 "Open Failed: Field 'Table' not found in Seamless "
298 "Dataset '%s'. This is type of file not currently "
299 "supported.",
300 m_pszFname);
301 Close();
302 return -1;
303 }
304
305 /*-----------------------------------------------------------------
306 * We need to open the first table to get its FeatureDefn
307 *----------------------------------------------------------------*/
308 if (OpenBaseTable(-1, bTestOpenNoError) != 0 )
309 {
310 // Open Failed... an error has already been reported, just return.
311 if (bTestOpenNoError)
312 CPLErrorReset();
313 Close();
314 return -1;
315 }
316
317 CPLAssert(m_poCurBaseTable);
318 m_poFeatureDefnRef = m_poCurBaseTable->GetLayerDefn();
319 m_poFeatureDefnRef->Reference();
320
321 return 0;
322 }
323
324
325 /**********************************************************************
326 * TABSeamless::Close()
327 *
328 * Close current file, and release all memory used.
329 *
330 * Returns 0 on success, -1 on error.
331 **********************************************************************/
Close()332 int TABSeamless::Close()
333 {
334 if (m_poIndexTable)
335 delete m_poIndexTable; // Automatically closes.
336 m_poIndexTable = NULL;
337
338 if (m_poFeatureDefnRef )
339 m_poFeatureDefnRef->Release();
340 m_poFeatureDefnRef = NULL;
341
342 if (m_poCurFeature)
343 delete m_poCurFeature;
344 m_poCurFeature = NULL;
345 m_nCurFeatureId = -1;
346
347 CPLFree(m_pszFname);
348 m_pszFname = NULL;
349
350 CPLFree(m_pszPath);
351 m_pszPath = NULL;
352
353 m_nTableNameField = -1;
354 m_nCurBaseTableId = -1;
355
356 if (m_poCurBaseTable)
357 delete m_poCurBaseTable;
358 m_poCurBaseTable = NULL;
359
360 return 0;
361 }
362
363 /**********************************************************************
364 * TABSeamless::OpenBaseTable()
365 *
366 * Open the base table for specified IndexFeature.
367 *
368 * Returns 0 on success, -1 on error.
369 **********************************************************************/
OpenBaseTable(TABFeature * poIndexFeature,GBool bTestOpenNoError)370 int TABSeamless::OpenBaseTable(TABFeature *poIndexFeature,
371 GBool bTestOpenNoError /*=FALSE*/)
372 {
373 CPLAssert(poIndexFeature);
374
375 /*-----------------------------------------------------------------
376 * Fetch table id. We actually use the index feature's ids as the
377 * base table ids.
378 *----------------------------------------------------------------*/
379 GIntBig nTableId64 = poIndexFeature->GetFID();
380 int nTableId = (int)nTableId64;
381 CPLAssert((GIntBig)nTableId == nTableId64);
382
383 if (m_nCurBaseTableId == nTableId && m_poCurBaseTable != NULL)
384 {
385 // The right table is already opened. Not much to do!
386 m_poCurBaseTable->ResetReading();
387 return 0;
388 }
389
390 // Close current base table
391 if (m_poCurBaseTable)
392 delete m_poCurBaseTable;
393 m_nCurBaseTableId = -1;
394
395 m_bEOF = FALSE;
396
397 /*-----------------------------------------------------------------
398 * Build full path to the table and open it.
399 * __TODO__ For now we assume that all table filename paths are relative
400 * but we may have to deal with absolute filenames as well.
401 *----------------------------------------------------------------*/
402 const char *pszName = poIndexFeature->GetFieldAsString(m_nTableNameField);
403 char *pszFname = CPLStrdup(CPLSPrintf("%s%s", m_pszPath, pszName));
404
405 #ifndef _WIN32
406 // On Unix, replace any '\\' in path with '/'
407 char *pszPtr = pszFname;
408 while((pszPtr = strchr(pszPtr, '\\')) != NULL)
409 {
410 *pszPtr = '/';
411 pszPtr++;
412 }
413 #endif
414
415 m_poCurBaseTable = new TABFile;
416 if (m_poCurBaseTable->Open(pszFname, m_eAccessMode, bTestOpenNoError) != 0)
417 {
418 // Open Failed... an error has already been reported, just return.
419 if (bTestOpenNoError)
420 CPLErrorReset();
421 delete m_poCurBaseTable;
422 m_poCurBaseTable = NULL;
423 CPLFree(pszFname);
424 return -1;
425 }
426
427 // Set the spatial filter to the new table
428 if( m_poFilterGeom != NULL && m_poCurBaseTable )
429 {
430 m_poCurBaseTable->SetSpatialFilter( m_poFilterGeom );
431 }
432
433 m_nCurBaseTableId = nTableId;
434 CPLFree(pszFname);
435
436 return 0;
437 }
438
439 /**********************************************************************
440 * TABSeamless::OpenBaseTable()
441 *
442 * Open the base table for specified IndexFeature.
443 *
444 * Returns 0 on success, -1 on error.
445 **********************************************************************/
OpenBaseTable(int nTableId,GBool bTestOpenNoError)446 int TABSeamless::OpenBaseTable(int nTableId, GBool bTestOpenNoError /*=FALSE*/)
447 {
448
449 if (nTableId == -1)
450 {
451 // Open first table from dataset
452 m_poIndexTable->ResetReading();
453 if (OpenNextBaseTable(bTestOpenNoError) != 0)
454 {
455 // Open Failed... an error has already been reported.
456 if (bTestOpenNoError)
457 CPLErrorReset();
458 return -1;
459 }
460 }
461 else if (nTableId == m_nCurBaseTableId && m_poCurBaseTable != NULL)
462 {
463 // The right table is already opened. Not much to do!
464 m_poCurBaseTable->ResetReading();
465 return 0;
466 }
467 else
468 {
469 TABFeature *poIndexFeature = m_poIndexTable->GetFeatureRef(nTableId);
470
471 if (poIndexFeature)
472 {
473 if (OpenBaseTable(poIndexFeature, bTestOpenNoError) != 0)
474 {
475 // Open Failed... an error has already been reported.
476 if (bTestOpenNoError)
477 CPLErrorReset();
478 return -1;
479 }
480 }
481 }
482
483 return 0;
484 }
485
486 /**********************************************************************
487 * TABSeamless::OpenNextBaseTable()
488 *
489 * Open the next base table in the dataset, using GetNextFeature() so that
490 * the spatial filter is respected.
491 *
492 * m_bEOF will be set if there are no more base tables to read.
493 *
494 * Returns 0 on success, -1 on error.
495 **********************************************************************/
OpenNextBaseTable(GBool bTestOpenNoError)496 int TABSeamless::OpenNextBaseTable(GBool bTestOpenNoError /*=FALSE*/)
497 {
498 CPLAssert(m_poIndexTable);
499
500 TABFeature *poIndexFeature = (TABFeature*)m_poIndexTable->GetNextFeature();
501
502 if (poIndexFeature)
503 {
504 if (OpenBaseTable(poIndexFeature, bTestOpenNoError) != 0)
505 {
506 // Open Failed... an error has already been reported.
507 if (bTestOpenNoError)
508 CPLErrorReset();
509 delete poIndexFeature;
510 return -1;
511 }
512 delete poIndexFeature;
513 m_bEOF = FALSE;
514 }
515 else
516 {
517 // Reached EOF
518 m_bEOF = TRUE;
519 }
520
521 return 0;
522 }
523
524
525 /**********************************************************************
526 * TABSeamless::EncodeFeatureId()
527 *
528 * Combine the table id + feature id into a single feature id that should
529 * be unique amongst all base tables in this seamless dataset.
530 **********************************************************************/
EncodeFeatureId(int nTableId,int nBaseFeatureId)531 GIntBig TABSeamless::EncodeFeatureId(int nTableId, int nBaseFeatureId)
532 {
533 if (nTableId == -1 || nBaseFeatureId == -1)
534 return -1;
535
536 /* Feature encoding is now based on the numbers of bits on the number
537 of features in the index table. */
538
539 return (((GIntBig)nTableId<<32) + nBaseFeatureId);
540 }
541
ExtractBaseTableId(GIntBig nEncodedFeatureId)542 int TABSeamless::ExtractBaseTableId(GIntBig nEncodedFeatureId)
543 {
544 if (nEncodedFeatureId == -1)
545 return -1;
546
547 return ((int)(nEncodedFeatureId>>32));
548 }
549
ExtractBaseFeatureId(GIntBig nEncodedFeatureId)550 int TABSeamless::ExtractBaseFeatureId(GIntBig nEncodedFeatureId)
551 {
552 if (nEncodedFeatureId == -1)
553 return -1;
554
555 return ((int)(nEncodedFeatureId & 0xffffffff));
556 }
557
558 /**********************************************************************
559 * TABSeamless::GetNextFeatureId()
560 *
561 * Returns feature id that follows nPrevId, or -1 if it is the
562 * last feature id. Pass nPrevId=-1 to fetch the first valid feature id.
563 **********************************************************************/
GetNextFeatureId(GIntBig nPrevId)564 GIntBig TABSeamless::GetNextFeatureId(GIntBig nPrevId)
565 {
566 if (m_poIndexTable == NULL)
567 return -1; // File is not opened yet
568
569 if (nPrevId == -1 || m_nCurBaseTableId != ExtractBaseTableId(nPrevId))
570 {
571 if (OpenBaseTable(ExtractBaseTableId(nPrevId)) != 0)
572 return -1;
573 }
574
575 int nId = ExtractBaseFeatureId(nPrevId);
576 do
577 {
578 nId = (int) m_poCurBaseTable->GetNextFeatureId(nId);
579 if (nId != -1)
580 return EncodeFeatureId(m_nCurBaseTableId, nId); // Found one!
581 else
582 OpenNextBaseTable(); // Skip to next tile and loop again
583
584 } while (nId == -1 && !m_bEOF && m_poCurBaseTable);
585
586 return -1;
587 }
588
589 /**********************************************************************
590 * TABSeamless::GetFeatureRef()
591 *
592 * Fill and return a TABFeature object for the specified feature id.
593 *
594 * The returned pointer is a reference to an object owned and maintained
595 * by this TABSeamless object. It should not be altered or freed by the
596 * caller and its contents is guaranteed to be valid only until the next
597 * call to GetFeatureRef() or Close().
598 *
599 * Returns NULL if the specified feature id does not exist of if an
600 * error happened. In any case, CPLError() will have been called to
601 * report the reason of the failure.
602 **********************************************************************/
GetFeatureRef(GIntBig nFeatureId)603 TABFeature *TABSeamless::GetFeatureRef(GIntBig nFeatureId)
604 {
605 if (m_poIndexTable == NULL)
606 return NULL; // File is not opened yet
607
608 if (nFeatureId == m_nCurFeatureId && m_poCurFeature)
609 return m_poCurFeature;
610
611 if (m_nCurBaseTableId != ExtractBaseTableId(nFeatureId))
612 {
613 if (OpenBaseTable(ExtractBaseTableId(nFeatureId)) != 0)
614 return NULL;
615 }
616
617 if (m_poCurBaseTable)
618 {
619 if (m_poCurFeature)
620 delete m_poCurFeature;
621 m_poCurFeature = NULL;
622
623 TABFeature* poCurFeature = (TABFeature*)m_poCurBaseTable->GetFeature(ExtractBaseFeatureId(nFeatureId));
624 if( poCurFeature == NULL )
625 return NULL;
626 m_poCurFeature = new TABFeature(m_poFeatureDefnRef);
627 m_poCurFeature->SetFrom(poCurFeature);
628 delete poCurFeature;
629
630 m_nCurFeatureId = nFeatureId;
631
632 m_poCurFeature->SetFID(nFeatureId);
633
634 return m_poCurFeature;
635 }
636
637 return NULL;
638 }
639
640
641 /**********************************************************************
642 * TABSeamless::GetLayerDefn()
643 *
644 * Returns a reference to the OGRFeatureDefn that will be used to create
645 * features in this dataset.
646 *
647 * Returns a reference to an object that is maintained by this TABSeamless
648 * object (and thus should not be modified or freed by the caller) or
649 * NULL if the OGRFeatureDefn has not been initialized yet (i.e. no file
650 * opened yet)
651 **********************************************************************/
GetLayerDefn()652 OGRFeatureDefn *TABSeamless::GetLayerDefn()
653 {
654 return m_poFeatureDefnRef;
655 }
656
657 /**********************************************************************
658 * TABSeamless::GetNativeFieldType()
659 *
660 * Returns the native MapInfo field type for the specified field.
661 *
662 * Returns TABFUnknown if file is not opened, or if specified field index is
663 * invalid.
664 *
665 * Note that field ids are positive and start at 0.
666 **********************************************************************/
GetNativeFieldType(int nFieldId)667 TABFieldType TABSeamless::GetNativeFieldType(int nFieldId)
668 {
669 if (m_poCurBaseTable)
670 return m_poCurBaseTable->GetNativeFieldType(nFieldId);
671
672 return TABFUnknown;
673 }
674
675
676
677 /**********************************************************************
678 * TABSeamless::IsFieldIndexed()
679 *
680 * Returns TRUE if field is indexed, or FALSE otherwise.
681 **********************************************************************/
IsFieldIndexed(int nFieldId)682 GBool TABSeamless::IsFieldIndexed(int nFieldId)
683 {
684 if (m_poCurBaseTable)
685 return m_poCurBaseTable->IsFieldIndexed(nFieldId);
686
687 return FALSE;
688 }
689
690 /**********************************************************************
691 * TABSeamless::IsFieldUnique()
692 *
693 * Returns TRUE if field is in the Unique table, or FALSE otherwise.
694 **********************************************************************/
IsFieldUnique(int nFieldId)695 GBool TABSeamless::IsFieldUnique(int nFieldId)
696 {
697 if (m_poCurBaseTable)
698 return m_poCurBaseTable->IsFieldUnique(nFieldId);
699
700 return FALSE;
701 }
702
703
704 /**********************************************************************
705 * TABSeamless::GetBounds()
706 *
707 * Fetch projection coordinates bounds of a dataset.
708 *
709 * The bForce flag has no effect on TAB files since the bounds are
710 * always in the header.
711 *
712 * Returns 0 on success, -1 on error.
713 **********************************************************************/
GetBounds(double & dXMin,double & dYMin,double & dXMax,double & dYMax,GBool bForce)714 int TABSeamless::GetBounds(double &dXMin, double &dYMin,
715 double &dXMax, double &dYMax,
716 GBool bForce /*= TRUE*/)
717 {
718 if (m_poIndexTable == NULL)
719 {
720 CPLError(CE_Failure, CPLE_AppDefined,
721 "GetBounds() can be called only after dataset has been opened.");
722 return -1;
723 }
724
725 return m_poIndexTable->GetBounds(dXMin, dYMin, dXMax, dYMax, bForce);
726 }
727
728 /**********************************************************************
729 * TABSeamless::GetExtent()
730 *
731 * Fetch extent of the data currently stored in the dataset.
732 *
733 * The bForce flag has no effect on TAB files since that value is
734 * always in the header.
735 *
736 * Returns OGRERR_NONE/OGRRERR_FAILURE.
737 **********************************************************************/
GetExtent(OGREnvelope * psExtent,int bForce)738 OGRErr TABSeamless::GetExtent (OGREnvelope *psExtent, int bForce)
739 {
740 if (m_poIndexTable == NULL)
741 {
742 CPLError(CE_Failure, CPLE_AppDefined,
743 "GetExtent() can be called only after dataset has been opened.");
744 return OGRERR_FAILURE;
745 }
746
747 return m_poIndexTable->GetExtent(psExtent, bForce);
748
749 }
750
751 /**********************************************************************
752 * TABSeamless::GetFeatureCountByType()
753 *
754 * Return number of features of each type.
755 *
756 * Note that the sum of the 4 returned values may be different from
757 * the total number of features since features with NONE geometry
758 * are not taken into account here.
759 *
760 * Returns 0 on success, or silently returns -1 (with no error) if this
761 * information is not available.
762 **********************************************************************/
GetFeatureCountByType(CPL_UNUSED int & numPoints,CPL_UNUSED int & numLines,CPL_UNUSED int & numRegions,CPL_UNUSED int & numTexts,CPL_UNUSED GBool bForce)763 int TABSeamless::GetFeatureCountByType(CPL_UNUSED int &numPoints,
764 CPL_UNUSED int &numLines,
765 CPL_UNUSED int &numRegions,
766 CPL_UNUSED int &numTexts,
767 CPL_UNUSED GBool bForce /*= TRUE*/)
768 {
769 /*-----------------------------------------------------------------
770 * __TODO__ This should be implemented to return -1 if force=false,
771 * or scan all the base tables if force=true
772 *----------------------------------------------------------------*/
773
774 return -1;
775 }
776
GetFeatureCount(int bForce)777 GIntBig TABSeamless::GetFeatureCount(int bForce)
778 {
779 /*-----------------------------------------------------------------
780 * __TODO__ This should be implemented to return -1 if force=false,
781 * or scan all the base tables if force=true
782 *----------------------------------------------------------------*/
783
784 return OGRLayer::GetFeatureCount(bForce);
785 }
786
787
788 /**********************************************************************
789 * TABSeamless::GetSpatialRef()
790 *
791 * Returns a reference to an OGRSpatialReference for this dataset.
792 * If the projection parameters have not been parsed yet, then we will
793 * parse them before returning.
794 *
795 * The returned object is owned and maintained by this TABFile and
796 * should not be modified or freed by the caller.
797 *
798 * Returns NULL if the SpatialRef cannot be accessed.
799 **********************************************************************/
GetSpatialRef()800 OGRSpatialReference *TABSeamless::GetSpatialRef()
801 {
802 if (m_poIndexTable == NULL)
803 {
804 CPLError(CE_Failure, CPLE_AssertionFailed,
805 "GetSpatialRef() failed: file has not been opened yet.");
806 return NULL;
807 }
808
809 return m_poIndexTable->GetSpatialRef();
810 }
811
812
813
814 /**********************************************************************
815 * IMapInfoFile::SetSpatialFilter()
816 *
817 * Standard OGR SetSpatialFiltere implementation. This methode is used
818 * to set a SpatialFilter for this OGRLayer
819 **********************************************************************/
SetSpatialFilter(OGRGeometry * poGeomIn)820 void TABSeamless::SetSpatialFilter (OGRGeometry * poGeomIn )
821
822 {
823 IMapInfoFile::SetSpatialFilter( poGeomIn );
824
825 if( m_poIndexTable )
826 m_poIndexTable->SetSpatialFilter( poGeomIn );
827
828 if( m_poCurBaseTable )
829 m_poCurBaseTable->SetSpatialFilter( poGeomIn );
830 }
831
832
833
834 /************************************************************************/
835 /* TestCapability() */
836 /************************************************************************/
837
TestCapability(const char * pszCap)838 int TABSeamless::TestCapability( const char * pszCap )
839
840 {
841 if( EQUAL(pszCap,OLCRandomRead) )
842 return TRUE;
843
844 else if( EQUAL(pszCap,OLCSequentialWrite)
845 || EQUAL(pszCap,OLCRandomWrite) )
846 return FALSE;
847
848 else if( EQUAL(pszCap,OLCFastFeatureCount) )
849 return FALSE;
850
851 else if( EQUAL(pszCap,OLCFastSpatialFilter) )
852 return FALSE;
853
854 else if( EQUAL(pszCap,OLCFastGetExtent) )
855 return TRUE;
856
857 else
858 return FALSE;
859 }
860
861
862
863 /**********************************************************************
864 * TABSeamless::Dump()
865 *
866 * Dump block contents... available only in DEBUG mode.
867 **********************************************************************/
868 #ifdef DEBUG
869
Dump(FILE * fpOut)870 void TABSeamless::Dump(FILE *fpOut /*=NULL*/)
871 {
872 if (fpOut == NULL)
873 fpOut = stdout;
874
875 fprintf(fpOut, "----- TABSeamless::Dump() -----\n");
876
877 if (m_poIndexTable == NULL)
878 {
879 fprintf(fpOut, "File is not opened.\n");
880 }
881 else
882 {
883 fprintf(fpOut, "File is opened: %s\n", m_pszFname);
884
885 }
886
887 fflush(fpOut);
888 }
889
890 #endif // DEBUG
891