LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_imapinfofile.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 143
Code covered: 65.0 % Executed lines: 93

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_imapinfofile.cpp,v 1.28 2008/11/17 22:06:21 aboudreault Exp $
       3                 :  *
       4                 :  * Name:     mitab_imapinfo
       5                 :  * Project:  MapInfo mid/mif Tab Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the IMapInfoFile class, super class of
       8                 :  *           of MIFFile and TABFile
       9                 :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
      10                 :  *
      11                 :  **********************************************************************
      12                 :  * Copyright (c) 1999-2008, 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_imapinfofile.cpp,v $
      34                 :  * Revision 1.28  2008/11/17 22:06:21  aboudreault
      35                 :  * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
      36                 :  * OGR and fixed reading/writing support for these types.
      37                 :  *
      38                 :  * Revision 1.27  2008/09/26 14:40:24  aboudreault
      39                 :  * Fixed bug: MITAB doesn't support writing DateTime type (bug 1948)
      40                 :  *
      41                 :  * Revision 1.26  2008/03/07 20:16:17  dmorissette
      42                 :  * Fixed typos in comments
      43                 :  *
      44                 :  * Revision 1.25  2008/03/05 20:35:39  dmorissette
      45                 :  * Replace MITAB 1.x SetFeature() with a CreateFeature() for V2.x (bug 1859)
      46                 :  *
      47                 :  * Revision 1.24  2007/06/21 14:00:23  dmorissette
      48                 :  * Added missing cast in isspace() calls to avoid failed assertion on Windows
      49                 :  * (MITAB bug 1737, GDAL ticket 1678))
      50                 :  *
      51                 :  * Revision 1.23  2007/06/12 14:43:19  dmorissette
      52                 :  * Use iswspace instead of sispace in IMapInfoFile::SmartOpen() (bug 1737)
      53                 :  *
      54                 :  * Revision 1.22  2007/06/12 13:52:37  dmorissette
      55                 :  * Added IMapInfoFile::SetCharset() method (bug 1734)
      56                 :  *
      57                 :  * Revision 1.21  2005/05/19 21:10:50  fwarmerdam
      58                 :  * changed to use OGRLayers spatial filter support
      59                 :  *
      60                 :  * Revision 1.20  2005/05/19 15:27:00  jlacroix
      61                 :  * Implement a method to set the StyleString of a TABFeature.
      62                 :  * This is done via the ITABFeaturePen, Brush and Symbol classes.
      63                 :  *
      64                 :  * Revision 1.19  2004/06/30 20:29:04  dmorissette
      65                 :  * Fixed refs to old address danmo@videotron.ca
      66                 :  *
      67                 :  * Revision 1.18  2003/12/19 07:55:55  fwarmerdam
      68                 :  * treat 3D features as 2D on write
      69                 :  *
      70                 :  * Revision 1.17  2001/09/14 19:14:43  warmerda
      71                 :  * added attribute query support
      72                 :  *
      73                 :  * Revision 1.16  2001/09/14 03:23:55  warmerda
      74                 :  * Substantial upgrade to support spatial queries using spatial indexes
      75                 :  *
      76                 :  * Revision 1.15  2001/07/03 23:11:21  daniel
      77                 :  * Test for NULL geometries if spatial filter enabled in GetNextFeature().
      78                 :  *
      79                 :  * Revision 1.14  2001/03/09 04:16:02  daniel
      80                 :  * Added TABSeamless for reading seamless TAB files
      81                 :  *
      82                 :  * Revision 1.13  2001/02/27 19:59:05  daniel
      83                 :  * Enabled spatial filter in IMapInfoFile::GetNextFeature(), and avoid
      84                 :  * unnecessary feature cloning in GetNextFeature() and GetFeature()
      85                 :  *
      86                 :  * Revision 1.12  2001/02/06 22:03:24  warmerda
      87                 :  * fixed memory leak of whole features in CreateFeature
      88                 :  *
      89                 :  * Revision 1.11  2001/01/23 21:23:42  daniel
      90                 :  * Added projection bounds lookup table, called from TABFile::SetProjInfo()
      91                 :  *
      92                 :  * Revision 1.10  2001/01/22 16:03:58  warmerda
      93                 :  * expanded tabs
      94                 :  *
      95                 :  * Revision 1.9  2000/11/30 20:27:56  warmerda
      96                 :  * make variable length string fields 254 wide, not 255
      97                 :  *
      98                 :  * Revision 1.8  2000/02/28 03:11:35  warmerda
      99                 :  * fix support for zero width fields
     100                 :  *
     101                 :  * Revision 1.7  2000/02/02 20:14:03  warmerda
     102                 :  * made safer when encountering geometryless features
     103                 :  *
     104                 :  * Revision 1.6  2000/01/26 18:17:35  warmerda
     105                 :  * added CreateField method
     106                 :  *
     107                 :  * Revision 1.5  2000/01/15 22:30:44  daniel
     108                 :  * Switch to MIT/X-Consortium OpenSource license
     109                 :  *
     110                 :  * Revision 1.4  2000/01/11 19:06:25  daniel
     111                 :  * Added support for conversion of collections in CreateFeature()
     112                 :  *
     113                 :  * Revision 1.3  1999/12/14 02:14:50  daniel
     114                 :  * Added static SmartOpen() method + TABView support
     115                 :  *
     116                 :  * Revision 1.2  1999/11/08 19:15:44  stephane
     117                 :  * Add headers method
     118                 :  *
     119                 :  * Revision 1.1  1999/11/08 04:17:27  stephane
     120                 :  * First Revision
     121                 :  *
     122                 :  **********************************************************************/
     123                 : 
     124                 : #include "mitab.h"
     125                 : #include "mitab_utils.h"
     126                 : 
     127                 : #ifdef __HP_aCC
     128                 : #  include <wchar.h>      /* iswspace() */
     129                 : #else
     130                 : #  include <wctype.h>      /* iswspace() */
     131                 : #endif
     132                 : 
     133                 : /**********************************************************************
     134                 :  *                   IMapInfoFile::IMapInfoFile()
     135                 :  *
     136                 :  * Constructor.
     137                 :  **********************************************************************/
     138              22 : IMapInfoFile::IMapInfoFile()
     139                 : {
     140              22 :     m_nCurFeatureId = 0;
     141              22 :     m_poCurFeature = NULL;
     142              22 :     m_bBoundsSet = FALSE;
     143              22 :     m_pszCharset = NULL;
     144              22 : }
     145                 : 
     146                 : 
     147                 : /**********************************************************************
     148                 :  *                   IMapInfoFile::~IMapInfoFile()
     149                 :  *
     150                 :  * Destructor.
     151                 :  **********************************************************************/
     152              22 : IMapInfoFile::~IMapInfoFile()
     153                 : {
     154              22 :     if (m_poCurFeature)
     155                 :     {
     156               0 :         delete m_poCurFeature;
     157               0 :         m_poCurFeature = NULL;
     158                 :     }
     159                 : 
     160              22 :     CPLFree(m_pszCharset);
     161              22 :     m_pszCharset = NULL;
     162              22 : }
     163                 : 
     164                 : /**********************************************************************
     165                 :  *                   IMapInfoFile::SmartOpen()
     166                 :  *
     167                 :  * Use this static method to automatically open any flavour of MapInfo
     168                 :  * dataset.  This method will detect the file type, create an object
     169                 :  * of the right type, and open the file.
     170                 :  *
     171                 :  * Call GetFileClass() on the returned object if you need to find out
     172                 :  * its exact type.  (To access format-specific methods for instance)
     173                 :  *
     174                 :  * Returns the new object ptr. , or NULL if the open failed.
     175                 :  **********************************************************************/
     176                 : IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname,
     177             167 :                                       GBool bTestOpenNoError /*=FALSE*/)
     178                 : {
     179             167 :     IMapInfoFile *poFile = NULL;
     180             167 :     int nLen = 0;
     181                 : 
     182             167 :     if (pszFname)
     183             167 :         nLen = strlen(pszFname);
     184                 : 
     185             178 :     if (nLen > 4 && (EQUAL(pszFname + nLen-4, ".MIF") ||
     186                 :                      EQUAL(pszFname + nLen-4, ".MID") ) )
     187                 :     {
     188                 :         /*-------------------------------------------------------------
     189                 :          * MIF/MID file
     190                 :          *------------------------------------------------------------*/
     191              11 :         poFile = new MIFFile;
     192                 :     }
     193             156 :     else if (nLen > 4 && EQUAL(pszFname + nLen-4, ".TAB"))
     194                 :     {
     195                 :         /*-------------------------------------------------------------
     196                 :          * .TAB file ... is it a TABFileView or a TABFile?
     197                 :          * We have to read the .tab header to find out.
     198                 :          *------------------------------------------------------------*/
     199                 :         FILE *fp;
     200                 :         const char *pszLine;
     201               2 :         char *pszAdjFname = CPLStrdup(pszFname);
     202               2 :         GBool bFoundFields = FALSE, bFoundView=FALSE, bFoundSeamless=FALSE;
     203                 : 
     204               2 :         TABAdjustFilenameExtension(pszAdjFname);
     205               2 :         fp = VSIFOpen(pszAdjFname, "r");
     206              22 :         while(fp && (pszLine = CPLReadLine(fp)) != NULL)
     207                 :         {
     208              18 :             while (isspace((unsigned char)*pszLine))  pszLine++;
     209              18 :             if (EQUALN(pszLine, "Fields", 6))
     210               2 :                 bFoundFields = TRUE;
     211              16 :             else if (EQUALN(pszLine, "create view", 11))
     212               0 :                 bFoundView = TRUE;
     213              16 :             else if (EQUALN(pszLine, "\"\\IsSeamless\" = \"TRUE\"", 21))
     214               0 :                 bFoundSeamless = TRUE;
     215                 :         }
     216                 : 
     217               2 :         if (bFoundView)
     218               0 :             poFile = new TABView;
     219               2 :         else if (bFoundFields && bFoundSeamless)
     220               0 :             poFile = new TABSeamless;
     221               2 :         else if (bFoundFields)
     222               2 :             poFile = new TABFile;
     223                 : 
     224               2 :         if (fp)
     225               2 :             VSIFClose(fp);
     226                 : 
     227               2 :         CPLFree(pszAdjFname);
     228                 :     }
     229                 : 
     230                 :     /*-----------------------------------------------------------------
     231                 :      * Perform the open() call
     232                 :      *----------------------------------------------------------------*/
     233             167 :     if (poFile && poFile->Open(pszFname, "r", bTestOpenNoError) != 0)
     234                 :     {
     235               0 :         delete poFile;
     236               0 :         poFile = NULL;
     237                 :     }
     238                 : 
     239             167 :     if (!bTestOpenNoError && poFile == NULL)
     240                 :     {
     241                 :         CPLError(CE_Failure, CPLE_FileIO,
     242               0 :                  "%s could not be opened as a MapInfo dataset.", pszFname);
     243                 :     }
     244                 : 
     245             167 :     return poFile;
     246                 : }
     247                 : 
     248                 : 
     249                 : 
     250                 : /**********************************************************************
     251                 :  *                   IMapInfoFile::GetNextFeature()
     252                 :  *
     253                 :  * Standard OGR GetNextFeature implementation.  This method is used
     254                 :  * to retreive the next OGRFeature.
     255                 :  **********************************************************************/
     256              69 : OGRFeature *IMapInfoFile::GetNextFeature()
     257                 : {
     258                 :     OGRFeature *poFeatureRef;
     259                 :     OGRGeometry *poGeom;
     260                 :     int nFeatureId;
     261                 : 
     262             176 :     while( (nFeatureId = GetNextFeatureId(m_nCurFeatureId)) != -1 )
     263                 :     {
     264              97 :         poFeatureRef = GetFeatureRef(nFeatureId);
     265              97 :         if (poFeatureRef == NULL)
     266               0 :             return NULL;
     267              97 :         else if( (m_poFilterGeom == NULL ||
     268                 :                   ((poGeom = poFeatureRef->GetGeometryRef()) != NULL &&
     269                 :                    FilterGeometry( poGeom )))
     270                 :                  && (m_poAttrQuery == NULL
     271                 :                      || m_poAttrQuery->Evaluate( poFeatureRef )) )
     272                 :         {
     273                 :             // Avoid cloning feature... return the copy owned by the class
     274              59 :             CPLAssert(poFeatureRef == m_poCurFeature);
     275              59 :             m_poCurFeature = NULL;  
     276              59 :             return poFeatureRef;
     277                 :         }
     278                 :     }
     279              10 :     return NULL;
     280                 : }
     281                 : 
     282                 : /**********************************************************************
     283                 :  *                   IMapInfoFile::CreateFeature()
     284                 :  *
     285                 :  * Standard OGR CreateFeature implementation.  This method is used
     286                 :  * to create a new feature in current dataset 
     287                 :  **********************************************************************/
     288              33 : OGRErr     IMapInfoFile::CreateFeature(OGRFeature *poFeature)
     289                 : {
     290                 :     TABFeature *poTABFeature;
     291                 :     OGRGeometry   *poGeom;
     292                 :     OGRwkbGeometryType eGType;
     293                 :     OGRErr  eErr;
     294              33 :     TABPoint *poTABPointFeature = NULL;
     295              33 :     TABRegion *poTABRegionFeature = NULL;
     296              33 :     TABPolyline *poTABPolylineFeature = NULL;
     297                 : 
     298                 :     /*-----------------------------------------------------------------
     299                 :      * MITAB won't accept new features unless they are in a type derived
     300                 :      * from TABFeature... so we have to do our best to map to the right
     301                 :      * feature type based on the geometry type.
     302                 :      *----------------------------------------------------------------*/
     303              33 :     poGeom = poFeature->GetGeometryRef();
     304              33 :     if( poGeom != NULL )
     305              26 :         eGType = poGeom->getGeometryType();
     306                 :     else
     307               7 :         eGType = wkbNone;
     308                 : 
     309              33 :     switch( wkbFlatten(eGType) )
     310                 :     {
     311                 :       /*-------------------------------------------------------------
     312                 :        * POINT
     313                 :        *------------------------------------------------------------*/
     314                 :       case wkbPoint:
     315               4 :         poTABFeature = new TABPoint(poFeature->GetDefnRef());
     316               4 :         if(poFeature->GetStyleString())
     317                 :         {
     318               0 :             poTABPointFeature = (TABPoint*)poTABFeature;
     319                 :             poTABPointFeature->SetSymbolFromStyleString(
     320               0 :                 poFeature->GetStyleString());
     321                 :         }
     322               4 :         break;
     323                 :       /*-------------------------------------------------------------
     324                 :        * REGION
     325                 :        *------------------------------------------------------------*/
     326                 :       case wkbPolygon:
     327                 :       case wkbMultiPolygon:
     328              21 :         poTABFeature = new TABRegion(poFeature->GetDefnRef());
     329              21 :         if(poFeature->GetStyleString())
     330                 :         {
     331               0 :             poTABRegionFeature = (TABRegion*)poTABFeature;
     332                 :             poTABRegionFeature->SetPenFromStyleString(
     333               0 :                 poFeature->GetStyleString());
     334                 : 
     335                 :             poTABRegionFeature->SetBrushFromStyleString(
     336               0 :                 poFeature->GetStyleString());
     337                 :         }
     338              21 :         break;
     339                 :       /*-------------------------------------------------------------
     340                 :        * LINE/PLINE/MULTIPLINE
     341                 :        *------------------------------------------------------------*/
     342                 :       case wkbLineString:
     343                 :       case wkbMultiLineString:
     344               1 :         poTABFeature = new TABPolyline(poFeature->GetDefnRef());
     345               1 :         if(poFeature->GetStyleString())
     346                 :         {
     347               0 :             poTABPolylineFeature = (TABPolyline*)poTABFeature;
     348                 :             poTABPolylineFeature->SetPenFromStyleString(
     349               0 :                 poFeature->GetStyleString());
     350                 :         }
     351               1 :         break;
     352                 :       /*-------------------------------------------------------------
     353                 :        * Collection types that are not directly supported... convert
     354                 :        * to multiple features in output file through recursive calls.
     355                 :        *------------------------------------------------------------*/
     356                 :       case wkbGeometryCollection:
     357                 :       case wkbMultiPoint:
     358                 :       {
     359               0 :           OGRErr eStatus = OGRERR_NONE;
     360                 :           int i;
     361               0 :           OGRGeometryCollection *poColl = (OGRGeometryCollection*)poGeom;
     362               0 :           OGRFeature *poTmpFeature = poFeature->Clone();
     363                 : 
     364               0 :           for (i=0; eStatus==OGRERR_NONE && i<poColl->getNumGeometries(); i++)
     365                 :           {
     366               0 :               poTmpFeature->SetGeometry(poColl->getGeometryRef(i));
     367               0 :               eStatus = CreateFeature(poTmpFeature);
     368                 :           }
     369               0 :           delete poTmpFeature;
     370               0 :           return eStatus;
     371                 :         }
     372                 :         break;
     373                 :       /*-------------------------------------------------------------
     374                 :        * Unsupported type.... convert to MapInfo geometry NONE
     375                 :        *------------------------------------------------------------*/
     376                 :       case wkbUnknown:
     377                 :       default:
     378               7 :          poTABFeature = new TABFeature(poFeature->GetDefnRef()); 
     379                 :         break;
     380                 :     }
     381                 : 
     382              33 :     if( poGeom != NULL )
     383              26 :         poTABFeature->SetGeometryDirectly(poGeom->clone());
     384                 :     
     385             110 :     for (int i=0; i< poFeature->GetDefnRef()->GetFieldCount();i++)
     386                 :     {
     387              77 :         poTABFeature->SetField(i,poFeature->GetRawFieldRef( i ));
     388                 :     }
     389                 :     
     390                 : 
     391              33 :     eErr = CreateFeature(poTABFeature);
     392                 : 
     393              33 :     delete poTABFeature;
     394                 :     
     395              33 :     return eErr;
     396                 : }
     397                 : 
     398                 : /**********************************************************************
     399                 :  *                   IMapInfoFile::GetFeature()
     400                 :  *
     401                 :  * Standard OGR GetFeature implementation.  This method is used
     402                 :  * to get the wanted (nFeatureId) feature, a NULL value will be 
     403                 :  * returned on error.
     404                 :  **********************************************************************/
     405               0 : OGRFeature *IMapInfoFile::GetFeature(long nFeatureId)
     406                 : {
     407                 :     OGRFeature *poFeatureRef;
     408                 : 
     409               0 :     poFeatureRef = GetFeatureRef(nFeatureId);
     410               0 :     if (poFeatureRef)
     411                 :     {
     412                 :         // Avoid cloning feature... return the copy owned by the class
     413               0 :         CPLAssert(poFeatureRef == m_poCurFeature);
     414               0 :         m_poCurFeature = NULL;  
     415                 : 
     416               0 :         return poFeatureRef;
     417                 :     }
     418                 :     else
     419               0 :       return NULL;
     420                 : }
     421                 : 
     422                 : /************************************************************************/
     423                 : /*                            CreateField()                             */
     424                 : /*                                                                      */
     425                 : /*      Create a native field based on a generic OGR definition.        */
     426                 : /************************************************************************/
     427                 : 
     428              17 : OGRErr IMapInfoFile::CreateField( OGRFieldDefn *poField, int bApproxOK )
     429                 : 
     430                 : {
     431                 :     TABFieldType        eTABType;
     432              17 :     int                 nWidth = poField->GetWidth();
     433                 : 
     434              17 :     if( poField->GetType() == OFTInteger )
     435                 :     {
     436               3 :         eTABType = TABFInteger;
     437               3 :         if( nWidth == 0 )
     438               3 :             nWidth = 12;
     439                 :     }
     440              14 :     else if( poField->GetType() == OFTReal )
     441                 :     {
     442               3 :         eTABType = TABFFloat;
     443               3 :         if( nWidth == 0 )
     444               3 :             nWidth = 32;
     445                 :     }
     446              11 :     else if( poField->GetType() == OFTDate )
     447                 :     {
     448               0 :         eTABType = TABFDate;
     449               0 :         if( nWidth == 0 )
     450               0 :             nWidth = 10;
     451                 :     }
     452              11 :     else if( poField->GetType() == OFTTime )
     453                 :     {
     454               0 :         eTABType = TABFTime;
     455               0 :         if( nWidth == 0 )
     456               0 :             nWidth = 8;
     457                 :     }
     458              11 :     else if( poField->GetType() == OFTDateTime )
     459                 :     {
     460               0 :         eTABType = TABFDateTime;
     461               0 :         if( nWidth == 0 )
     462               0 :             nWidth = 19;
     463                 :     }
     464              11 :     else if( poField->GetType() == OFTString )
     465                 :     {
     466              11 :         eTABType = TABFChar;
     467              11 :         if( nWidth == 0 )
     468              11 :             nWidth = 254;
     469                 :         else
     470               0 :             nWidth = MIN(254,nWidth);
     471                 :     }
     472                 :     else
     473                 :     {
     474                 :         CPLError( CE_Failure, CPLE_AppDefined,
     475                 :                   "IMapInfoFile::CreateField() called with unsupported field"
     476                 :                   " type %d.\n"
     477                 :                   "Note that Mapinfo files don't support list field types.\n",
     478               0 :                   poField->GetType() );
     479                 : 
     480               0 :         return OGRERR_FAILURE;
     481                 :     }
     482                 : 
     483              17 :     if( AddFieldNative( poField->GetNameRef(), eTABType,
     484                 :                         nWidth, poField->GetPrecision() ) > -1 )
     485              17 :         return OGRERR_NONE;
     486                 :     else
     487               0 :         return OGRERR_FAILURE;
     488                 : }
     489                 : 
     490                 : 
     491                 : /**********************************************************************
     492                 :  *                   IMapInfoFile::SetCharset()
     493                 :  *
     494                 :  * Set the charset for the tab header. 
     495                 :  *
     496                 :  *
     497                 :  * Returns 0 on success, -1 on error.
     498                 :  **********************************************************************/
     499               0 : int IMapInfoFile::SetCharset(const char* pszCharset)
     500                 : {
     501               0 :     if(pszCharset && strlen(pszCharset) > 0)
     502                 :     {
     503               0 :         CPLFree(m_pszCharset);
     504               0 :         m_pszCharset = CPLStrdup(pszCharset);
     505                 :     }
     506               0 :     return 0;
     507                 : }
     508                 : 

Generated by: LTP GCOV extension version 1.5