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 270 57.4 %
Date: 2024-05-05 22:37:24 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             :  * 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

Generated by: LCOV version 1.14