LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_idfile.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 106 65 61.3 %
Date: 2012-12-26 Functions: 10 6 60.0 %

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_idfile.cpp,v 1.8 2006-11-28 18:49:08 dmorissette Exp $
       3                 :  *
       4                 :  * Name:     mitab_idfile.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the TABIDFile class used to handle
       8                 :  *           reading/writing of the .ID file attached to a .MAP file
       9                 :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
      10                 :  *
      11                 :  **********************************************************************
      12                 :  * Copyright (c) 1999, 2000, 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_idfile.cpp,v $
      34                 :  * Revision 1.8  2006-11-28 18:49:08  dmorissette
      35                 :  * Completed changes to split TABMAPObjectBlocks properly and produce an
      36                 :  * optimal spatial index (bug 1585)
      37                 :  *
      38                 :  * Revision 1.7  2004/06/30 20:29:04  dmorissette
      39                 :  * Fixed refs to old address danmo@videotron.ca
      40                 :  *
      41                 :  * Revision 1.6  2000/01/18 22:08:56  daniel
      42                 :  * Allow opening of 0-size .ID file (dataset with 0 features)
      43                 :  *
      44                 :  * Revision 1.5  2000/01/15 22:30:44  daniel
      45                 :  * Switch to MIT/X-Consortium OpenSource license
      46                 :  *
      47                 :  * Revision 1.4  1999/09/26 14:59:36  daniel
      48                 :  * Implemented write support
      49                 :  *
      50                 :  * Revision 1.3  1999/09/20 18:43:01  daniel
      51                 :  * Use binary acces to open file.
      52                 :  *
      53                 :  * Revision 1.2  1999/09/16 02:39:16  daniel
      54                 :  * Completed read support for most feature types
      55                 :  *
      56                 :  * Revision 1.1  1999/07/12 04:18:24  daniel
      57                 :  * Initial checkin
      58                 :  *
      59                 :  **********************************************************************/
      60                 : 
      61                 : #include "mitab.h"
      62                 : #include "mitab_utils.h"
      63                 : 
      64                 : /*=====================================================================
      65                 :  *                      class TABIDFile
      66                 :  *====================================================================*/
      67                 : 
      68                 : 
      69                 : /**********************************************************************
      70                 :  *                   TABIDFile::TABIDFile()
      71                 :  *
      72                 :  * Constructor.
      73                 :  **********************************************************************/
      74               6 : TABIDFile::TABIDFile()
      75                 : {
      76               6 :     m_fp = NULL;
      77               6 :     m_pszFname = NULL;
      78               6 :     m_poIDBlock = NULL;
      79               6 :     m_nMaxId = -1;
      80               6 : }
      81                 : 
      82                 : /**********************************************************************
      83                 :  *                   TABIDFile::~TABIDFile()
      84                 :  *
      85                 :  * Destructor.
      86                 :  **********************************************************************/
      87               6 : TABIDFile::~TABIDFile()
      88                 : {
      89               6 :     Close();
      90               6 : }
      91                 : 
      92                 : /**********************************************************************
      93                 :  *                   TABIDFile::Open()
      94                 :  *
      95                 :  * Open a .ID file, and initialize the structures to be ready to read
      96                 :  * objects from it.
      97                 :  *
      98                 :  * If the filename that is passed in contains a .MAP extension then
      99                 :  * the extension will be changed to .ID before trying to open the file.
     100                 :  *
     101                 :  * Returns 0 on success, -1 on error.
     102                 :  **********************************************************************/
     103               6 : int TABIDFile::Open(const char *pszFname, const char *pszAccess)
     104                 : {
     105                 :     int         nLen;
     106                 : 
     107               6 :     if (m_fp)
     108                 :     {
     109                 :         CPLError(CE_Failure, CPLE_FileIO,
     110               0 :                  "Open() failed: object already contains an open file");
     111               0 :         return -1;
     112                 :     }
     113                 : 
     114                 :     /*-----------------------------------------------------------------
     115                 :      * Validate access mode and make sure we use binary access.
     116                 :      * Note that in Write mode we need TABReadWrite since we do random
     117                 :      * updates in the index as data blocks are split
     118                 :      *----------------------------------------------------------------*/
     119               6 :     if (EQUALN(pszAccess, "r", 1))
     120                 :     {
     121               3 :         m_eAccessMode = TABRead;
     122               3 :         pszAccess = "rb";
     123                 :     }
     124               3 :     else if (EQUALN(pszAccess, "w", 1))
     125                 :     {
     126               3 :         m_eAccessMode = TABReadWrite;
     127               3 :         pszAccess = "wb+";
     128                 :     }
     129                 :     else
     130                 :     {
     131                 :         CPLError(CE_Failure, CPLE_FileIO,
     132               0 :                  "Open() failed: access mode \"%s\" not supported", pszAccess);
     133               0 :         return -1;
     134                 :     }
     135                 : 
     136                 :     /*-----------------------------------------------------------------
     137                 :      * Change .MAP extension to .ID if necessary
     138                 :      *----------------------------------------------------------------*/
     139               6 :     m_pszFname = CPLStrdup(pszFname);
     140                 : 
     141               6 :     nLen = strlen(m_pszFname);
     142               6 :     if (nLen > 4 && strcmp(m_pszFname+nLen-4, ".MAP")==0)
     143               0 :         strcpy(m_pszFname+nLen-4, ".ID");
     144               6 :     else if (nLen > 4 && strcmp(m_pszFname+nLen-4, ".map")==0)
     145               6 :         strcpy(m_pszFname+nLen-4, ".id");
     146                 : 
     147                 :     /*-----------------------------------------------------------------
     148                 :      * Change .MAP extension to .ID if necessary
     149                 :      *----------------------------------------------------------------*/
     150                 : #ifndef _WIN32
     151               6 :     TABAdjustFilenameExtension(m_pszFname);
     152                 : #endif
     153                 : 
     154                 :     /*-----------------------------------------------------------------
     155                 :      * Open file
     156                 :      *----------------------------------------------------------------*/
     157               6 :     m_fp = VSIFOpen(m_pszFname, pszAccess);
     158                 : 
     159               6 :     if (m_fp == NULL)
     160                 :     {
     161                 :         CPLError(CE_Failure, CPLE_FileIO,
     162               0 :                  "Open() failed for %s", m_pszFname);
     163               0 :         CPLFree(m_pszFname);
     164               0 :         m_pszFname = NULL;
     165               0 :         return -1;
     166                 :     }
     167                 : 
     168               6 :     if (m_eAccessMode == TABRead)
     169                 :     {
     170                 :         /*-------------------------------------------------------------
     171                 :          * READ access:
     172                 :          * Establish the number of object IDs from the size of the file
     173                 :          *------------------------------------------------------------*/
     174                 :         VSIStatBuf  sStatBuf;
     175               3 :         if ( VSIStat(m_pszFname, &sStatBuf) == -1 )
     176                 :         {
     177                 :             CPLError(CE_Failure, CPLE_FileIO, 
     178               0 :                      "stat() failed for %s\n", m_pszFname);
     179               0 :             Close();
     180               0 :             return -1;
     181                 :         }
     182                 : 
     183               3 :         m_nMaxId = sStatBuf.st_size/4;
     184               3 :         m_nBlockSize = MIN(1024, m_nMaxId*4);
     185                 : 
     186                 :         /*-------------------------------------------------------------
     187                 :          * Read the first block from the file
     188                 :          *------------------------------------------------------------*/
     189               3 :         m_poIDBlock = new TABRawBinBlock(m_eAccessMode, FALSE);
     190                 : 
     191               3 :         if (m_nMaxId == 0)
     192                 :         {
     193                 :             // .ID file size = 0 ... just allocate a blank block but
     194                 :             // it won't get really used anyways.
     195               0 :             m_nBlockSize = 512;
     196               0 :             m_poIDBlock->InitNewBlock(m_fp, m_nBlockSize, 0);
     197                 :         }
     198               3 :         else if (m_poIDBlock->ReadFromFile(m_fp, 0, m_nBlockSize) != 0)
     199                 :         {
     200                 :             // CPLError() has already been called.
     201               0 :             Close();
     202               0 :             return -1;
     203                 :         }
     204                 :     }
     205                 :     else
     206                 :     {
     207                 :         /*-------------------------------------------------------------
     208                 :          * WRITE access:
     209                 :          * Get ready to write to the file
     210                 :          *------------------------------------------------------------*/
     211               3 :         m_poIDBlock = new TABRawBinBlock(m_eAccessMode, FALSE);
     212               3 :         m_nMaxId = 0;
     213               3 :         m_nBlockSize = 1024;
     214               3 :         m_poIDBlock->InitNewBlock(m_fp, m_nBlockSize, 0);
     215                 :     }
     216                 : 
     217               6 :     return 0;
     218                 : }
     219                 : 
     220                 : /**********************************************************************
     221                 :  *                   TABIDFile::Close()
     222                 :  *
     223                 :  * Close current file, and release all memory used.
     224                 :  *
     225                 :  * Returns 0 on success, -1 on error.
     226                 :  **********************************************************************/
     227              12 : int TABIDFile::Close()
     228                 : {
     229              12 :     if (m_fp == NULL)
     230               6 :         return 0;
     231                 : 
     232                 :     /*----------------------------------------------------------------
     233                 :      * Write access: commit latest changes to the file.
     234                 :      *---------------------------------------------------------------*/
     235               6 :     if (m_eAccessMode == TABReadWrite && m_poIDBlock)
     236                 :     {
     237               3 :         m_poIDBlock->CommitToFile();
     238                 :     }
     239                 :     
     240                 :     // Delete all structures 
     241               6 :     delete m_poIDBlock;
     242               6 :     m_poIDBlock = NULL;
     243                 : 
     244                 :     // Close file
     245               6 :     VSIFClose(m_fp);
     246               6 :     m_fp = NULL;
     247                 : 
     248               6 :     CPLFree(m_pszFname);
     249               6 :     m_pszFname = NULL;
     250                 : 
     251               6 :     return 0;
     252                 : }
     253                 : 
     254                 : 
     255                 : /**********************************************************************
     256                 :  *                   TABIDFile::GetObjPtr()
     257                 :  *
     258                 :  * Return the offset in the .MAP file where the map object with the
     259                 :  * specified id is located.
     260                 :  *
     261                 :  * Note that object ids are positive and start at 1.
     262                 :  *
     263                 :  * An object Id of '0' means that object has no geometry.
     264                 :  *
     265                 :  * Returns a value >= 0 on success, -1 on error.
     266                 :  **********************************************************************/
     267              43 : GInt32 TABIDFile::GetObjPtr(GInt32 nObjId)
     268                 : {
     269              43 :     if (m_poIDBlock == NULL)
     270               0 :         return -1;
     271                 : 
     272              43 :     if (nObjId < 1 || nObjId > m_nMaxId)
     273                 :     {
     274                 :         CPLError(CE_Failure, CPLE_IllegalArg,
     275                 :                  "GetObjPtr(): Invalid object ID %d (valid range is [1..%d])",
     276               0 :                  nObjId, m_nMaxId);
     277               0 :         return -1;
     278                 :     }
     279                 : 
     280              43 :     if (m_poIDBlock->GotoByteInFile( (nObjId-1)*4 ) != 0)
     281               0 :         return -1;
     282                 : 
     283              43 :     return m_poIDBlock->ReadInt32();
     284                 : }
     285                 : 
     286                 : /**********************************************************************
     287                 :  *                   TABIDFile::SetObjPtr()
     288                 :  *
     289                 :  * Set the offset in the .MAP file where the map object with the
     290                 :  * specified id is located.
     291                 :  *
     292                 :  * Note that object ids are positive and start at 1.
     293                 :  *
     294                 :  * An object Id of '0' means that object has no geometry.
     295                 :  *
     296                 :  * Returns a value of 0 on success, -1 on error.
     297                 :  **********************************************************************/
     298              14 : int TABIDFile::SetObjPtr(GInt32 nObjId, GInt32 nObjPtr)
     299                 : {
     300              14 :     if (m_poIDBlock == NULL)
     301               0 :         return -1;
     302                 : 
     303              14 :     if (m_eAccessMode != TABReadWrite)
     304                 :     {
     305                 :         CPLError(CE_Failure, CPLE_NotSupported,
     306               0 :                  "SetObjPtr() can be used only with Write access.");
     307               0 :         return -1;
     308                 :     }
     309                 : 
     310              14 :     if (nObjId < 1)
     311                 :     {
     312                 :         CPLError(CE_Failure, CPLE_IllegalArg,
     313                 :                "SetObjPtr(): Invalid object ID %d (must be greater than zero)",
     314               0 :                  nObjId);
     315               0 :         return -1;
     316                 :     }
     317                 : 
     318                 :     /*-----------------------------------------------------------------
     319                 :      * GotoByteInFile() will automagically commit current block and init
     320                 :      * a new one if necessary.
     321                 :      *----------------------------------------------------------------*/
     322              14 :     GInt32 nLastIdBlock = ((m_nMaxId-1)*4) / m_nBlockSize;
     323              14 :     GInt32 nTargetIdBlock = ((nObjId-1)*4) / m_nBlockSize;
     324              25 :     if (m_nMaxId > 0 && nTargetIdBlock <= nLastIdBlock)
     325                 :     {
     326                 :         /* Pass second arg to GotoByteInFile() to force reading from file
     327                 :          * when going back to blocks already committed
     328                 :          */
     329              11 :         if (m_poIDBlock->GotoByteInFile( (nObjId-1)*4, TRUE ) != 0)
     330               0 :             return -1;
     331                 :     }
     332                 :     else
     333                 :     {
     334                 :         /* If we reach EOF then a new empty block will have to be allocated
     335                 :          */
     336               3 :         if (m_poIDBlock->GotoByteInFile( (nObjId-1)*4 ) != 0)
     337               0 :             return -1;
     338                 :     }
     339                 : 
     340              14 :     m_nMaxId = MAX(m_nMaxId, nObjId);
     341                 : 
     342              14 :     return m_poIDBlock->WriteInt32(nObjPtr);
     343                 : }
     344                 : 
     345                 : 
     346                 : /**********************************************************************
     347                 :  *                   TABIDFile::GetMaxObjId()
     348                 :  *
     349                 :  * Return the value of the biggest valid object id.
     350                 :  *
     351                 :  * Note that object ids are positive and start at 1.
     352                 :  *
     353                 :  * Returns a value >= 0 on success, -1 on error.
     354                 :  **********************************************************************/
     355               0 : GInt32 TABIDFile::GetMaxObjId()
     356                 : {
     357               0 :     return m_nMaxId;
     358                 : }
     359                 : 
     360                 : 
     361                 : /**********************************************************************
     362                 :  *                   TABIDFile::Dump()
     363                 :  *
     364                 :  * Dump block contents... available only in DEBUG mode.
     365                 :  **********************************************************************/
     366                 : #ifdef DEBUG
     367                 : 
     368               0 : void TABIDFile::Dump(FILE *fpOut /*=NULL*/)
     369                 : {
     370               0 :     if (fpOut == NULL)
     371               0 :         fpOut = stdout;
     372                 : 
     373               0 :     fprintf(fpOut, "----- TABIDFile::Dump() -----\n");
     374                 : 
     375               0 :     if (m_fp == NULL)
     376                 :     {
     377               0 :         fprintf(fpOut, "File is not opened.\n");
     378                 :     }
     379                 :     else
     380                 :     {
     381               0 :         fprintf(fpOut, "File is opened: %s\n", m_pszFname);
     382               0 :         fprintf(fpOut, "Current index block follows ...\n\n");
     383               0 :         m_poIDBlock->Dump(fpOut);
     384               0 :         fprintf(fpOut, "... end of index block.\n\n");
     385                 : 
     386                 :     }
     387                 : 
     388               0 :     fflush(fpOut);
     389               0 : }
     390                 : 
     391                 : #endif // DEBUG
     392                 : 
     393                 : 
     394                 : 
     395                 : 
     396                 : 

Generated by: LCOV version 1.7