LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/mitab - mitab_tabseamless.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 155 272 57.0 %
Date: 2024-11-21 22:18:42 Functions: 17 27 63.0 %

          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

Generated by: LCOV version 1.14