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