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