LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_tabseamless.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 271
Code covered: 0.0 % Executed lines: 0

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

Generated by: LTP GCOV extension version 1.5