LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_tabseamless.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 286 0 0.0 %
Date: 2012-04-28 Functions: 29 0 0.0 %

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

Generated by: LCOV version 1.7