LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_miffile.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 762 337 44.2 %
Date: 2010-01-09 Functions: 32 17 53.1 %

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_miffile.cpp,v 1.49 2008/11/17 22:06:21 aboudreault Exp $
       3                 :  *
       4                 :  * Name:     mitab_miffile.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the MIDFile class.
       8                 :  *           To be used by external programs to handle reading/writing of
       9                 :  *           features from/to MID/MIF datasets.
      10                 :  * Author:   Stephane Villeneuve, stephane.v@videotron.ca
      11                 :  *
      12                 :  **********************************************************************
      13                 :  * Copyright (c) 1999-2003, Stephane Villeneuve
      14                 :  *
      15                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      16                 :  * copy of this software and associated documentation files (the "Software"),
      17                 :  * to deal in the Software without restriction, including without limitation
      18                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      19                 :  * and/or sell copies of the Software, and to permit persons to whom the
      20                 :  * Software is furnished to do so, subject to the following conditions:
      21                 :  * 
      22                 :  * The above copyright notice and this permission notice shall be included
      23                 :  * in all copies or substantial portions of the Software.
      24                 :  * 
      25                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      26                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      27                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      28                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      29                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      30                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      31                 :  * DEALINGS IN THE SOFTWARE.
      32                 :  **********************************************************************
      33                 :  *
      34                 :  * $Log: mitab_miffile.cpp,v $
      35                 :  * Revision 1.49  2008/11/17 22:06:21  aboudreault
      36                 :  * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
      37                 :  * OGR and fixed reading/writing support for these types.
      38                 :  *
      39                 :  * Revision 1.48  2008/09/26 14:40:24  aboudreault
      40                 :  * Fixed bug: MITAB doesn't support writing DateTime type (bug 1948)
      41                 :  *
      42                 :  * Revision 1.47  2008/03/05 20:35:39  dmorissette
      43                 :  * Replace MITAB 1.x SetFeature() with a CreateFeature() for V2.x (bug 1859)
      44                 :  *
      45                 :  * Revision 1.46  2008/02/01 20:30:59  dmorissette
      46                 :  * Use %.15g instead of %.16g as number precision in .MIF output
      47                 :  *
      48                 :  * Revision 1.45  2008/01/29 21:56:39  dmorissette
      49                 :  * Update dataset version properly for Date/Time/DateTime field types (#1754)
      50                 :  *
      51                 :  * Revision 1.44  2008/01/29 20:46:32  dmorissette
      52                 :  * Added support for v9 Time and DateTime fields (byg 1754)
      53                 :  *
      54                 :  * Revision 1.43  2007/09/14 15:35:21  dmorissette
      55                 :  * Fixed problem with MIF parser being confused by special attribute
      56                 :  * names (bug 1795)
      57                 :  *
      58                 :  * Revision 1.42  2007/06/12 13:52:37  dmorissette
      59                 :  * Added IMapInfoFile::SetCharset() method (bug 1734)
      60                 :  *
      61                 :  * Revision 1.41  2005/10/13 20:12:03  fwarmerdam
      62                 :  * layers with just regions can't be set as type wkbPolygon because they may
      63                 :  * have multipolygons (bug GDAL:958)
      64                 :  *     http://bugzilla.remotesensing.org/show_bug.cgi?id=958
      65                 :  *
      66                 :  * Revision 1.40  2005/10/12 14:03:02  fwarmerdam
      67                 :  * Fixed problem with white space parsing in mitab_miffile.cpp (bug GDAL:954)
      68                 :  *
      69                 :  * Revision 1.39  2005/10/04 19:36:10  dmorissette
      70                 :  * Added support for reading collections from MIF files (bug 1126)
      71                 :  *
      72                 :  * Revision 1.38  2004/02/27 21:04:14  fwarmerdam
      73                 :  * dont write MIF header if file is readonly - gdal bugzilla 509
      74                 :  *
      75                 :  * Revision 1.37  2003/12/19 07:54:50  fwarmerdam
      76                 :  * write mif header on close if not already written out
      77                 :  *
      78                 :  * Revision 1.36  2003/08/13 02:49:02  dmorissette
      79                 :  * Use tab as default delimiter if not explicitly specified (Anthony D, bug 37)
      80                 :  *
      81                 :  * Revision 1.35  2003/01/30 22:42:39  daniel
      82                 :  * Fixed crash in ParseMIFHeader() when .mif doesn't contain a DATA line
      83                 :  *
      84                 :  * Revision 1.34  2002/09/23 12:53:29  warmerda
      85                 :  * fix memory leak of m_pszIndex
      86                 :  *
      87                 :  * Revision 1.33  2002/05/08 15:10:48  julien
      88                 :  * Implement MIFFile::SetMIFCoordSys in mitab_capi.cpp (Bug 984)
      89                 :  *
      90                 :  * Revision 1.32  2002/04/26 14:16:49  julien
      91                 :  * Finishing the implementation of Multipoint (support for MIF)
      92                 :  *
      93                 :  * Revision 1.31  2001/09/19 21:39:15  warmerda
      94                 :  * get extents efficiently
      95                 :  *
      96                 :  * Revision 1.30  2001/09/19 14:31:22  warmerda
      97                 :  * added m_nPreloadedId to keep track of preloaded line
      98                 :  *
      99                 :  * Revision 1.29  2001/09/14 19:14:43  warmerda
     100                 :  * added attribute query support
     101                 :  *
     102                 :  * Revision 1.28  2001/08/10 17:49:01  warmerda
     103                 :  * fixed a few memory leaks
     104                 :  *
     105                 :  * Revision 1.27  2001/03/15 03:57:51  daniel
     106                 :  * Added implementation for new OGRLayer::GetExtent(), returning data MBR.
     107                 :  *
     108                 :  * Revision 1.26  2001/03/09 04:14:19  daniel
     109                 :  * Fixed problem creating new files with mixed case extensions (e.g. ".Tab")
     110                 :  *
     111                 :  * Revision 1.25  2001/03/09 03:51:48  daniel
     112                 :  * Fixed writing MIF header: missing break; for decimal fields
     113                 :  *
     114                 :  * Revision 1.24  2001/02/27 19:59:05  daniel
     115                 :  * Enabled spatial filter in IMapInfoFile::GetNextFeature(), and avoid
     116                 :  * unnecessary feature cloning in GetNextFeature() and GetFeature()
     117                 :  *
     118                 :  * Revision 1.23  2001/01/23 21:23:42  daniel
     119                 :  * Added projection bounds lookup table, called from TABFile::SetProjInfo()
     120                 :  *
     121                 :  * Revision 1.22  2001/01/22 16:03:58  warmerda
     122                 :  * expanded tabs
     123                 :  *
     124                 :  * Revision 1.21  2000/12/15 05:38:38  daniel
     125                 :  * Produce Warning instead of an error when nWidth>254 in AddFieldNative()
     126                 :  *
     127                 :  * Revision 1.20  2000/11/14 06:15:37  daniel
     128                 :  * Handle '\t' as spaces in parsing, and fixed GotoFeature() to avoid calling
     129                 :  * ResetReading() when reading forward.
     130                 :  *
     131                 :  * Revision 1.19  2000/07/04 01:50:40  warmerda
     132                 :  * Removed unprotected debugging printf.
     133                 :  *
     134                 :  * Revision 1.18  2000/06/28 00:32:04  warmerda
     135                 :  * Make GetFeatureCountByType() actually work if bForce is TRUE
     136                 :  * Collect detailed (by feature type) feature counts in PreParse().
     137                 :  *
     138                 :  * Revision 1.17  2000/04/27 15:46:25  daniel
     139                 :  * Make SetFeatureDefn() use AddFieldNative(), scan field names for invalid
     140                 :  * chars, and map field width=0 (variable length in OGR) to valid defaults
     141                 :  *
     142                 :  * Revision 1.16  2000/03/27 03:37:59  daniel
     143                 :  * Handle bounds in CoordSys for read and write, + handle point SYMBOL line as
     144                 :  * optional + fixed reading of bounds in PreParseFile()
     145                 :  *
     146                 :  * Revision 1.15  2000/02/28 17:05:06  daniel
     147                 :  * Added support for index and unique directives for read and write
     148                 :  *
     149                 :  * Revision 1.14  2000/01/28 07:32:25  daniel
     150                 :  * Validate char field width (must be <= 254 chars)
     151                 :  *
     152                 :  * Revision 1.13  2000/01/24 19:51:33  warmerda
     153                 :  * AddFieldNative should not fail for read-only datasets
     154                 :  *
     155                 :  * Revision 1.12  2000/01/18 23:13:41  daniel
     156                 :  * Implemented AddFieldNative()
     157                 :  *
     158                 :  * ...
     159                 :  *
     160                 :  * Revision 1.1  1999/11/08 04:16:07  stephane
     161                 :  * First Revision
     162                 :  *
     163                 :  **********************************************************************/
     164                 : 
     165                 : #include "mitab.h"
     166                 : #include "mitab_utils.h"
     167                 : #include <ctype.h>
     168                 : 
     169                 : /*=====================================================================
     170                 :  *                      class MIFFile
     171                 :  *====================================================================*/
     172                 : 
     173                 : 
     174                 : /**********************************************************************
     175                 :  *                   MIFFile::MIFFile()
     176                 :  *
     177                 :  * Constructor.
     178                 :  **********************************************************************/
     179               9 : MIFFile::MIFFile()
     180                 : {
     181               9 :     m_pszFname = NULL;
     182               9 :     m_nVersion = 300;
     183                 : 
     184                 :     // Tab is default delimiter in MIF spec if not explicitly specified.  Use
     185                 :     // that by default for read mode. In write mode, we will use "," as 
     186                 :     // delimiter since it's more common than tab (we do this in Open())
     187               9 :     m_pszDelimiter = CPLStrdup("\t");
     188                 : 
     189               9 :     m_pszUnique = NULL;
     190               9 :     m_pszIndex = NULL;
     191               9 :     m_pszCoordSys = NULL;
     192                 : 
     193               9 :     m_paeFieldType = NULL;
     194               9 :     m_pabFieldIndexed = NULL;
     195               9 :     m_pabFieldUnique = NULL;
     196                 : 
     197               9 :     m_dfXMultiplier = 1.0;
     198               9 :     m_dfYMultiplier = 1.0;
     199               9 :     m_dfXDisplacement = 0.0;
     200               9 :     m_dfYDisplacement = 0.0;
     201                 : 
     202               9 :     m_poMIDFile = NULL;
     203               9 :     m_poMIFFile = NULL;
     204               9 :     m_nPreloadedId = 0;
     205                 : 
     206               9 :     m_poDefn = NULL;
     207               9 :     m_poSpatialRef = NULL;
     208                 : 
     209               9 :     m_nCurFeatureId = 0;
     210               9 :     m_nFeatureCount = 0;
     211               9 :     m_nWriteFeatureId = -1;
     212               9 :     m_poCurFeature = NULL;
     213                 :    
     214               9 :     m_bPreParsed = FALSE;
     215               9 :     m_nAttribut = 0;
     216               9 :     m_bHeaderWrote = FALSE;
     217               9 :     m_nPoints = m_nLines = m_nRegions = m_nTexts = 0;
     218                 : 
     219               9 :     m_bExtentsSet = FALSE;
     220               9 : }
     221                 : 
     222                 : /**********************************************************************
     223                 :  *                   MIFFile::~MIFFile()
     224                 :  *
     225                 :  * Destructor.
     226                 :  **********************************************************************/
     227              18 : MIFFile::~MIFFile()
     228                 : {
     229               9 :     Close();
     230              18 : }
     231                 : 
     232                 : /**********************************************************************
     233                 :  *                   MIFFile::Open()
     234                 :  *
     235                 :  * Returns 0 on success, -1 on error.
     236                 :  **********************************************************************/
     237               9 : int MIFFile::Open(const char *pszFname, const char *pszAccess,
     238                 :                   GBool bTestOpenNoError /*=FALSE*/ )
     239                 : {
     240               9 :     char *pszTmpFname = NULL;
     241               9 :     int nFnameLen = 0;
     242                 :     
     243               9 :     CPLErrorReset();
     244                 : 
     245               9 :     if (m_poMIDFile)
     246                 :     {
     247                 :         CPLError(CE_Failure, CPLE_FileIO,
     248               0 :                      "Open() failed: object already contains an open file");
     249                 : 
     250               0 :         return -1;
     251                 :     }
     252                 : 
     253                 :     /*-----------------------------------------------------------------
     254                 :      * Validate access mode
     255                 :      *----------------------------------------------------------------*/
     256               9 :     if (EQUALN(pszAccess, "r", 1))
     257                 :     {
     258               7 :         m_eAccessMode = TABRead;
     259               7 :         pszAccess = "rt";
     260                 :     }
     261               2 :     else if (EQUALN(pszAccess, "w", 1))
     262                 :     {
     263               2 :         m_eAccessMode = TABWrite;
     264               2 :         pszAccess = "wt";
     265                 : 
     266                 :         // In write mode, use "," as delimiter since it's more common than tab
     267               2 :         CPLFree(m_pszDelimiter);
     268               2 :         m_pszDelimiter = CPLStrdup(",");
     269                 :     }
     270                 :     else
     271                 :     {
     272               0 :         if (!bTestOpenNoError)
     273                 :             CPLError(CE_Failure, CPLE_FileIO,
     274               0 :                  "Open() failed: access mode \"%s\" not supported", pszAccess);
     275                 :         else
     276               0 :             CPLErrorReset();
     277                 : 
     278               0 :         return -1;
     279                 :     }
     280                 : 
     281                 :     /*-----------------------------------------------------------------
     282                 :      * Make sure filename has a .MIF or .MID extension... 
     283                 :      *----------------------------------------------------------------*/
     284               9 :     m_pszFname = CPLStrdup(pszFname);
     285               9 :     nFnameLen = strlen(m_pszFname);
     286               9 :     if (nFnameLen > 4 && (strcmp(m_pszFname+nFnameLen-4, ".MID")==0 ||
     287                 :                      strcmp(m_pszFname+nFnameLen-4, ".MIF")==0 ) )
     288               0 :         strcpy(m_pszFname+nFnameLen-4, ".MIF");
     289              18 :     else if (nFnameLen > 4 && (EQUAL(m_pszFname+nFnameLen-4, ".mid") ||
     290                 :                                EQUAL(m_pszFname+nFnameLen-4, ".mif") ) )
     291               9 :         strcpy(m_pszFname+nFnameLen-4, ".mif");
     292                 :     else
     293                 :     {
     294               0 :         if (!bTestOpenNoError)
     295                 :             CPLError(CE_Failure, CPLE_FileIO,
     296                 :                      "Open() failed for %s: invalid filename extension",
     297               0 :                      m_pszFname);
     298                 :         else
     299               0 :             CPLErrorReset();
     300                 : 
     301               0 :         CPLFree(m_pszFname);
     302               0 :         return -1;
     303                 :     }
     304                 : 
     305               9 :     pszTmpFname = CPLStrdup(m_pszFname);
     306                 : 
     307                 :     /*-----------------------------------------------------------------
     308                 :      * Open .MIF file
     309                 :      *----------------------------------------------------------------*/
     310                 : 
     311                 : #ifndef _WIN32
     312                 :     /*-----------------------------------------------------------------
     313                 :      * On Unix, make sure extension uses the right cases
     314                 :      * We do it even for write access because if a file with the same
     315                 :      * extension already exists we want to overwrite it.
     316                 :      *----------------------------------------------------------------*/
     317               9 :     TABAdjustFilenameExtension(pszTmpFname);
     318                 : #endif
     319                 : 
     320               9 :     m_poMIFFile = new MIDDATAFile;
     321                 : 
     322               9 :     if (m_poMIFFile->Open(pszTmpFname, pszAccess) != 0)
     323                 :     {
     324               0 :         if (!bTestOpenNoError)
     325                 :             CPLError(CE_Failure, CPLE_NotSupported,
     326               0 :                      "Unable to open %s.", pszTmpFname);
     327                 :         else
     328               0 :             CPLErrorReset();
     329                 : 
     330               0 :         CPLFree(pszTmpFname);
     331               0 :         Close();
     332                 : 
     333               0 :         return -1;
     334                 :     }
     335                 : 
     336                 :     /*-----------------------------------------------------------------
     337                 :      * Open .MID file
     338                 :      *----------------------------------------------------------------*/
     339               9 :     if (nFnameLen > 4 && strcmp(pszTmpFname+nFnameLen-4, ".MIF")==0)
     340               0 :         strcpy(pszTmpFname+nFnameLen-4, ".MID");
     341                 :     else 
     342               9 :         strcpy(pszTmpFname+nFnameLen-4, ".mid");
     343                 : 
     344                 : #ifndef _WIN32
     345               9 :     TABAdjustFilenameExtension(pszTmpFname);
     346                 : #endif
     347                 : 
     348               9 :     m_poMIDFile = new MIDDATAFile;
     349                 : 
     350               9 :     if (m_poMIDFile->Open(pszTmpFname, pszAccess) !=0)
     351                 :     {
     352               0 :         if (!bTestOpenNoError)
     353                 :             CPLError(CE_Failure, CPLE_NotSupported,
     354               0 :                      "Unable to open %s.", pszTmpFname);
     355                 :         else
     356               0 :             CPLErrorReset();
     357                 : 
     358               0 :         CPLFree(pszTmpFname);
     359               0 :         Close();
     360                 : 
     361               0 :         return -1;
     362                 :     }
     363                 : 
     364                 : 
     365               9 :     CPLFree(pszTmpFname);
     366               9 :     pszTmpFname = NULL;
     367                 : 
     368                 :     /*-----------------------------------------------------------------
     369                 :      * Read MIF File Header
     370                 :      *----------------------------------------------------------------*/
     371               9 :     if (m_eAccessMode == TABRead && ParseMIFHeader() != 0)
     372                 :     {
     373               0 :         Close();
     374                 : 
     375               0 :         if (!bTestOpenNoError)
     376                 :             CPLError(CE_Failure, CPLE_NotSupported,
     377               0 :                      "Failed parsing header in %s.", m_pszFname);
     378                 :         else
     379               0 :             CPLErrorReset();
     380                 : 
     381               0 :         return -1;
     382                 :     }
     383                 : 
     384                 :     /*-----------------------------------------------------------------
     385                 :      * In write access, set some defaults
     386                 :      *----------------------------------------------------------------*/
     387               9 :     if (m_eAccessMode == TABWrite)
     388                 :     {
     389               2 :         m_nVersion = 300;
     390               2 :         m_pszCharset = CPLStrdup("Neutral");
     391                 :     }
     392                 : 
     393                 :     /* Put the MID file at the correct location, on the first feature */
     394               9 :     if (m_eAccessMode == TABRead && (m_poMIDFile->GetLine() == NULL))
     395                 :     {
     396               0 :         Close();
     397                 : 
     398               0 :         if (bTestOpenNoError)
     399               0 :             CPLErrorReset();
     400                 : 
     401               0 :         return -1;
     402                 :     }
     403                 : 
     404                 :     m_poMIFFile->SetTranslation(m_dfXMultiplier,m_dfYMultiplier,
     405               9 :                                 m_dfXDisplacement, m_dfYDisplacement);
     406                 :     m_poMIDFile->SetTranslation(m_dfXMultiplier,m_dfYMultiplier,
     407               9 :                                 m_dfXDisplacement, m_dfYDisplacement);
     408               9 :     m_poMIFFile->SetDelimiter(m_pszDelimiter);
     409               9 :     m_poMIDFile->SetDelimiter(m_pszDelimiter);
     410                 : 
     411                 :     /*-------------------------------------------------------------
     412                 :      * Set geometry type if the geometry objects are uniform.
     413                 :      *------------------------------------------------------------*/
     414               9 :     int numPoints=0, numRegions=0, numTexts=0, numLines=0;
     415                 : 
     416               9 :     if( GetFeatureCountByType( numPoints, numLines, numRegions, numTexts, 
     417               9 :                                FALSE ) == 0 )
     418                 :     {
     419               0 :         numPoints += numTexts;
     420               0 :         if( numPoints > 0 && numLines == 0 && numRegions == 0 )
     421               0 :             m_poDefn->SetGeomType( wkbPoint );
     422               0 :         else if( numPoints == 0 && numLines > 0 && numRegions == 0 )
     423               0 :             m_poDefn->SetGeomType( wkbLineString );
     424                 :         else
     425                 :             /* we leave it unknown indicating a mixture */;
     426                 :     }
     427                 : 
     428               9 :     return 0;
     429                 : }
     430                 : 
     431                 : /**********************************************************************
     432                 :  *                   MIFFile::ParseMIFHeader()
     433                 :  *
     434                 :  * Scan the header of a MIF file, and store any useful information into
     435                 :  * class members.  The main piece of information being the fields 
     436                 :  * definition that we use to build the OGRFeatureDefn for this file.
     437                 :  *
     438                 :  * This private method should be used only during the Open() call.
     439                 :  *
     440                 :  * Returns 0 on success, -1 on error.
     441                 :  **********************************************************************/
     442               7 : int MIFFile::ParseMIFHeader()
     443                 : {  
     444               7 :     GBool  bColumns = FALSE;
     445               7 :     int    nColumns = 0;
     446               7 :     GBool  bCoordSys = FALSE;
     447                 :     char  *pszTmp;
     448                 :             
     449                 :     
     450                 :     const char *pszLine;
     451                 :     char **papszToken;
     452                 : 
     453               7 :     char *pszFeatureClassName = TABGetBasename(m_pszFname);
     454               7 :     m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
     455               7 :     CPLFree(pszFeatureClassName);
     456                 :     // Ref count defaults to 0... set it to 1
     457               7 :     m_poDefn->Reference();
     458                 : 
     459                 :     
     460               7 :     if (m_eAccessMode != TABRead)
     461                 :     {
     462                 :         CPLError(CE_Failure, CPLE_NotSupported,
     463               0 :                  "ParseMIDFile() can be used only with Read access.");
     464               0 :         return -1;
     465                 :     }
     466                 :     
     467                 : 
     468                 :     /*-----------------------------------------------------------------
     469                 :      * Parse header until we find the "Data" line
     470                 :      *----------------------------------------------------------------*/
     471              91 :     while (((pszLine = m_poMIFFile->GetLine()) != NULL) && 
     472                 :            !(EQUALN(pszLine,"Data",4)))
     473                 :     {
     474             232 :         while(pszLine && (*pszLine == ' ' || *pszLine == '\t') )
     475              78 :             pszLine++;  // skip leading spaces
     476                 : 
     477             116 :         if (bColumns == TRUE && nColumns >0)
     478                 :         {
     479              39 :             if (nColumns == 0)
     480                 :             {
     481                 :                 // Permit to 0 columns
     482               0 :                 bColumns = FALSE;
     483                 :             }
     484              39 :             else if (AddFields(pszLine) == 0)
     485                 :             {
     486              39 :                 nColumns--;
     487              39 :                 if (nColumns == 0)
     488               7 :                   bColumns = FALSE;
     489                 :             }
     490                 :             else
     491                 :             {
     492               0 :                 bColumns = FALSE;
     493                 :             }
     494                 :         }
     495              38 :         else if (EQUALN(pszLine,"VERSION",7))
     496                 :         {
     497               7 :             papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE); 
     498               7 :             bColumns = FALSE; bCoordSys = FALSE;
     499               7 :             if (CSLCount(papszToken)  == 2)
     500               7 :               m_nVersion = atoi(papszToken[1]);
     501                 : 
     502               7 :             CSLDestroy(papszToken);
     503                 :         
     504                 :         }
     505              31 :         else if (EQUALN(pszLine,"CHARSET",7))
     506                 :         {
     507               7 :             papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE); 
     508               7 :             bColumns = FALSE; bCoordSys = FALSE;
     509                 :           
     510               7 :             if (CSLCount(papszToken)  == 2)
     511                 :             {
     512               7 :                 CPLFree(m_pszCharset);
     513               7 :                 m_pszCharset = CPLStrdup(papszToken[1]);
     514                 :             }
     515               7 :             CSLDestroy(papszToken);
     516                 :         
     517                 :         }
     518              24 :         else if (EQUALN(pszLine,"DELIMITER",9))
     519                 :         {
     520               7 :             papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE); 
     521               7 :              bColumns = FALSE; bCoordSys = FALSE;
     522                 :           
     523               7 :            if (CSLCount(papszToken)  == 2)
     524                 :            {
     525               7 :                CPLFree(m_pszDelimiter);
     526               7 :                m_pszDelimiter = CPLStrdup(papszToken[1]);    
     527                 :            }
     528               7 :           CSLDestroy(papszToken);
     529                 :         
     530                 :         }
     531              17 :         else if (EQUALN(pszLine,"UNIQUE",6))
     532                 :         {
     533               0 :             bColumns = FALSE; bCoordSys = FALSE;
     534                 :           
     535               0 :             m_pszUnique = CPLStrdup(pszLine + 6);
     536                 :         }
     537              17 :         else if (EQUALN(pszLine,"INDEX",5))
     538                 :         {
     539               0 :             bColumns = FALSE; bCoordSys = FALSE;
     540                 :           
     541               0 :             m_pszIndex = CPLStrdup(pszLine + 5);
     542                 :         }
     543              17 :         else if (EQUALN(pszLine,"COORDSYS",8) )
     544                 :         {
     545               5 :             bCoordSys = TRUE;
     546               5 :             m_pszCoordSys = CPLStrdup(pszLine + 9);
     547                 : 
     548                 :             // Extract bounds if present
     549                 :             char  **papszFields;
     550                 :             papszFields = CSLTokenizeStringComplex(m_pszCoordSys, " ,()\t",
     551               5 :                                                    TRUE, FALSE );
     552               5 :             int iBounds = CSLFindString( papszFields, "Bounds" );
     553               5 :             if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
     554                 :             {
     555               5 :                 m_dXMin = atof(papszFields[++iBounds]);
     556               5 :                 m_dYMin = atof(papszFields[++iBounds]);
     557               5 :                 m_dXMax = atof(papszFields[++iBounds]);
     558               5 :                 m_dYMax = atof(papszFields[++iBounds]);
     559               5 :                 m_bBoundsSet = TRUE;
     560                 :             }
     561               5 :             CSLDestroy( papszFields );
     562                 :         }
     563              12 :         else if (EQUALN(pszLine,"TRANSFORM",9))
     564                 :         {
     565               0 :             papszToken = CSLTokenizeStringComplex(pszLine," ,\t",TRUE,FALSE); 
     566               0 :             bColumns = FALSE; bCoordSys = FALSE;
     567                 :           
     568               0 :             if (CSLCount(papszToken) == 5)
     569                 :             {
     570               0 :                 m_dfXMultiplier   = atof(papszToken[1]);
     571               0 :                 m_dfYMultiplier   = atof(papszToken[2]);
     572               0 :                 m_dfXDisplacement = atof(papszToken[3]);
     573               0 :                 m_dfYDisplacement = atof(papszToken[4]);
     574                 :                 
     575               0 :                 if (m_dfXMultiplier == 0.0)
     576               0 :                   m_dfXMultiplier = 1.0;
     577               0 :                 if (m_dfYMultiplier == 0.0)
     578               0 :                   m_dfYMultiplier = 1.0;
     579                 :             }
     580               0 :             CSLDestroy(papszToken);
     581                 :         }
     582              12 :         else if (EQUALN(pszLine,"COLUMNS",7))
     583                 :         {
     584               7 :             papszToken = CSLTokenizeStringComplex(pszLine," ()\t",TRUE,FALSE); 
     585               7 :             bCoordSys = FALSE;
     586               7 :             bColumns = TRUE;
     587               7 :             if (CSLCount(papszToken) == 2)
     588                 :             {
     589               7 :                 nColumns = atoi(papszToken[1]);
     590               7 :                 m_nAttribut = nColumns;
     591                 :             }
     592                 :             else
     593                 :             {
     594               0 :                 bColumns = FALSE;
     595               0 :                 m_nAttribut = 0;
     596                 :             }
     597               7 :             CSLDestroy(papszToken);
     598                 :         }
     599               5 :         else if (bCoordSys == TRUE)
     600                 :         {
     601               0 :             pszTmp = m_pszCoordSys;
     602                 :             m_pszCoordSys = CPLStrdup(CPLSPrintf("%s %s",m_pszCoordSys,
     603               0 :                                                  pszLine));
     604               0 :             CPLFree(pszTmp);
     605                 :             //printf("Reading CoordSys\n");
     606                 :             // Reading CoordSys
     607                 :         }
     608                 : 
     609                 :     }
     610                 :     
     611               7 :     if ((pszLine = m_poMIFFile->GetLastLine()) == NULL || 
     612                 :         EQUALN(m_poMIFFile->GetLastLine(),"DATA",4) == FALSE)
     613                 :     {
     614                 :         CPLError(CE_Failure, CPLE_NotSupported,
     615                 :                  "DATA keyword not found in %s.  File may be corrupt.",
     616               0 :                  m_pszFname);
     617               0 :         return -1;
     618                 :     }
     619                 :     
     620                 :     /*-----------------------------------------------------------------
     621                 :      * Move pointer to first line of first object
     622                 :      *----------------------------------------------------------------*/
     623               9 :     while (((pszLine = m_poMIFFile->GetLine()) != NULL) && 
     624                 :            m_poMIFFile->IsValidFeature(pszLine) == FALSE)
     625                 :         ;
     626                 : 
     627                 :     /*-----------------------------------------------------------------
     628                 :      * Check for Unique and Indexed flags
     629                 :      *----------------------------------------------------------------*/
     630               7 :     if (m_pszIndex)
     631                 :     {
     632               0 :         papszToken = CSLTokenizeStringComplex(m_pszIndex," ,\t",TRUE,FALSE);
     633               0 :         for(int i=0; papszToken && papszToken[i]; i++)
     634                 :         {
     635               0 :             int nVal = atoi(papszToken[i]);
     636               0 :             if (nVal > 0 && nVal <= m_poDefn->GetFieldCount())
     637               0 :                 m_pabFieldIndexed[nVal-1] = TRUE;
     638                 :         }
     639               0 :         CSLDestroy(papszToken);
     640                 :     }
     641                 : 
     642               7 :     if (m_pszUnique)
     643                 :     {
     644               0 :         papszToken = CSLTokenizeStringComplex(m_pszUnique," ,\t",TRUE,FALSE);
     645               0 :         for(int i=0; papszToken && papszToken[i]; i++)
     646                 :         {
     647               0 :             int nVal = atoi(papszToken[i]);
     648               0 :             if (nVal > 0 && nVal <= m_poDefn->GetFieldCount())
     649               0 :                 m_pabFieldUnique[nVal-1] = TRUE;
     650                 :         }
     651               0 :         CSLDestroy(papszToken);
     652                 :     }
     653                 : 
     654               7 :     return 0;
     655                 : 
     656                 : }
     657                 : 
     658                 : /************************************************************************/
     659                 : /*                             AddFields()                              */
     660                 : /************************************************************************/
     661                 : 
     662              39 : int  MIFFile::AddFields(const char *pszLine)
     663                 : {
     664                 :     char **papszToken;
     665              39 :     int nStatus = 0,numTok;
     666                 : 
     667                 :     CPLAssert(m_bHeaderWrote == FALSE);
     668              39 :     papszToken = CSLTokenizeStringComplex(pszLine," (,)\t",TRUE,FALSE); 
     669              39 :     numTok = CSLCount(papszToken);
     670                 : 
     671              55 :     if (numTok >= 3 && EQUAL(papszToken[1], "char"))
     672                 :     {
     673                 :         /*-------------------------------------------------
     674                 :          * CHAR type
     675                 :          *------------------------------------------------*/
     676              16 :         nStatus = AddFieldNative(papszToken[0], TABFChar,
     677              32 :                                  atoi(papszToken[2]));
     678                 :     }
     679              35 :     else if (numTok >= 2 && EQUAL(papszToken[1], "integer"))
     680                 :     {
     681                 :         /*-------------------------------------------------
     682                 :          * INTEGER type
     683                 :          *------------------------------------------------*/
     684              12 :         nStatus = AddFieldNative(papszToken[0], TABFInteger);
     685                 :     }
     686              11 :     else if (numTok >= 2 && EQUAL(papszToken[1], "smallint"))
     687                 :     {
     688                 :         /*-------------------------------------------------
     689                 :          * SMALLINT type
     690                 :          *------------------------------------------------*/
     691               0 :         nStatus = AddFieldNative(papszToken[0], TABFSmallInt);
     692                 :     }
     693              11 :     else if (numTok >= 4 && EQUAL(papszToken[1], "decimal"))
     694                 :     {
     695                 :         /*-------------------------------------------------
     696                 :          * DECIMAL type
     697                 :          *------------------------------------------------*/
     698               0 :         nStatus = AddFieldNative(papszToken[0], TABFDecimal,
     699               0 :                                  atoi(papszToken[2]), atoi(papszToken[3]));
     700                 :     }
     701              22 :     else if (numTok >= 2 && EQUAL(papszToken[1], "float"))
     702                 :     {
     703                 :         /*-------------------------------------------------
     704                 :          * FLOAT type
     705                 :          *------------------------------------------------*/
     706              11 :         nStatus = AddFieldNative(papszToken[0], TABFFloat);
     707                 :     }
     708               0 :     else if (numTok >= 2 && EQUAL(papszToken[1], "date"))
     709                 :     {
     710                 :         /*-------------------------------------------------
     711                 :          * DATE type (returned as a string: "DD/MM/YYYY" or "YYYYMMDD")
     712                 :          *------------------------------------------------*/
     713               0 :         nStatus = AddFieldNative(papszToken[0], TABFDate);
     714                 :     }
     715               0 :     else if (numTok >= 2 && EQUAL(papszToken[1], "time"))
     716                 :     {
     717                 :         /*-------------------------------------------------
     718                 :          *  TIME type (v900, returned as a string: "HH:MM:SS" or "HHMMSSmmm")
     719                 :          *------------------------------------------------*/
     720               0 :         nStatus = AddFieldNative(papszToken[0], TABFTime);
     721                 :     }
     722               0 :     else if (numTok >= 2 && EQUAL(papszToken[1], "datetime"))
     723                 :     {
     724                 :         /*-------------------------------------------------
     725                 :          * DATETIME type (v900, returned as a string: "DD/MM/YYYY HH:MM:SS",
     726                 :          * "YYYY/MM/DD HH:MM:SS" or "YYYYMMDDHHMMSSmmm")
     727                 :          *------------------------------------------------*/
     728               0 :         nStatus = AddFieldNative(papszToken[0], TABFDateTime);
     729                 :     }
     730               0 :     else if (numTok >= 2 && EQUAL(papszToken[1], "logical"))
     731                 :     {
     732                 :         /*-------------------------------------------------
     733                 :          * LOGICAL type (value "T" or "F")
     734                 :          *------------------------------------------------*/
     735               0 :         nStatus = AddFieldNative(papszToken[0], TABFLogical);
     736                 :     }
     737                 :     else 
     738               0 :       nStatus = -1; // Unrecognized field type or line corrupt
     739                 :     
     740              39 :     CSLDestroy(papszToken);
     741              39 :     papszToken = NULL;
     742                 : 
     743              39 :     if (nStatus != 0)
     744                 :     {
     745                 :         CPLError(CE_Failure, CPLE_FileIO,
     746               0 :                  "Failed to parse field definition in file %s", m_pszFname);
     747               0 :         return -1;
     748                 :     }
     749                 :     
     750              39 :     return 0;
     751                 : }
     752                 : 
     753                 : /************************************************************************/
     754                 : /*                          GetFeatureCount()                           */
     755                 : /************************************************************************/
     756                 : 
     757               0 : int MIFFile::GetFeatureCount (int bForce)
     758                 : {
     759                 :     
     760               0 :     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
     761               0 :         return OGRLayer::GetFeatureCount( bForce );
     762                 :     else
     763                 :     {
     764               0 :         if (bForce == TRUE)
     765               0 :             PreParseFile();
     766                 : 
     767               0 :         if (m_bPreParsed)
     768               0 :             return m_nFeatureCount;
     769                 :         else
     770               0 :             return -1;
     771                 :     }
     772                 : }
     773                 : 
     774                 : /************************************************************************/
     775                 : /*                            ResetReading()                            */
     776                 : /************************************************************************/
     777                 : 
     778              12 : void MIFFile::ResetReading()
     779                 : 
     780                 : {   
     781                 :     const char *pszLine;
     782                 : 
     783              12 :     m_poMIFFile->Rewind();
     784                 : 
     785              12 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
     786             140 :       if (EQUALN(pszLine,"DATA",4))
     787              12 :         break;
     788                 : 
     789              28 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
     790                 :     {
     791              16 :         if (m_poMIFFile->IsValidFeature(pszLine))
     792              12 :           break;
     793                 :     }
     794                 : 
     795              12 :     m_poMIDFile->Rewind();
     796              12 :     m_poMIDFile->GetLine();
     797                 :     
     798                 :     // We're positioned on first feature.  Feature Ids start at 1.
     799              12 :     if (m_poCurFeature)
     800                 :     {
     801               1 :         delete m_poCurFeature;
     802               1 :         m_poCurFeature = NULL;
     803                 :     }
     804                 : 
     805              12 :     m_nCurFeatureId = 0;
     806              12 :     m_nPreloadedId = 1;
     807              12 : }
     808                 : 
     809                 : /************************************************************************/
     810                 : /*                            PreParseFile()                            */
     811                 : /************************************************************************/
     812                 : 
     813               0 : void MIFFile::PreParseFile()
     814                 : {
     815               0 :     char **papszToken = NULL;
     816                 :     const char *pszLine;
     817                 :     
     818               0 :     GBool bPLine = FALSE;
     819               0 :     GBool bText = FALSE;
     820                 : 
     821               0 :     if (m_bPreParsed == TRUE)
     822               0 :       return;
     823                 : 
     824               0 :     m_poMIFFile->Rewind();
     825                 : 
     826               0 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
     827               0 :       if (EQUALN(pszLine,"DATA",4))
     828               0 :         break;
     829                 : 
     830               0 :     m_nPoints = m_nLines = m_nRegions = m_nTexts = 0;
     831                 : 
     832               0 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
     833                 :     {
     834               0 :         if (m_poMIFFile->IsValidFeature(pszLine))
     835                 :         {
     836               0 :             bPLine = FALSE;
     837               0 :             bText = FALSE;
     838               0 :             m_nFeatureCount++;
     839                 :         }
     840                 : 
     841               0 :         CSLDestroy(papszToken);
     842               0 :         papszToken = CSLTokenizeString(pszLine);
     843                 : 
     844               0 :         if (EQUALN(pszLine,"POINT",5))
     845                 :         {
     846               0 :             m_nPoints++;
     847               0 :             if (CSLCount(papszToken) == 3)
     848                 :             {
     849               0 :                 UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[1])),
     850               0 :                              m_poMIFFile->GetYTrans(atof(papszToken[2])));
     851                 :             }
     852                 :               
     853                 :         }
     854               0 :         else if (EQUALN(pszLine,"LINE",4) ||
     855                 :                  EQUALN(pszLine,"RECT",4) ||
     856                 :                  EQUALN(pszLine,"ROUNDRECT",9) ||
     857                 :                  EQUALN(pszLine,"ARC",3) ||
     858                 :                  EQUALN(pszLine,"ELLIPSE",7))
     859                 :         {
     860               0 :             if (CSLCount(papszToken) == 5)
     861                 :             {
     862               0 :                 m_nLines++;
     863               0 :                 UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[1])), 
     864               0 :                              m_poMIFFile->GetYTrans(atof(papszToken[2])));
     865               0 :                 UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[3])), 
     866               0 :                              m_poMIFFile->GetYTrans(atof(papszToken[4])));
     867                 :             }
     868                 :         }
     869               0 :         else if (EQUALN(pszLine,"REGION",6) )
     870                 :         {
     871               0 :             m_nRegions++;
     872               0 :             bPLine = TRUE;
     873                 :         }
     874               0 :         else if( EQUALN(pszLine,"PLINE",5))
     875                 :         {
     876               0 :             m_nLines++;
     877               0 :             bPLine = TRUE;
     878                 :         }
     879               0 :         else if (EQUALN(pszLine,"TEXT",4)) 
     880                 :         {
     881               0 :             m_nTexts++;
     882               0 :             bText = TRUE;
     883                 :         }
     884               0 :         else if (bPLine == TRUE)
     885                 :         {
     886               0 :             if (CSLCount(papszToken) == 2 &&
     887               0 :                 strchr("-.0123456789", papszToken[0][0]) != NULL)
     888                 :             {
     889               0 :                 UpdateExtents( m_poMIFFile->GetXTrans(atof(papszToken[0])),
     890               0 :                               m_poMIFFile->GetYTrans(atof(papszToken[1])));
     891                 :             }
     892                 :         }
     893               0 :         else if (bText == TRUE)
     894                 :         {
     895               0 :            if (CSLCount(papszToken) == 4 &&
     896               0 :                 strchr("-.0123456789", papszToken[0][0]) != NULL)
     897                 :             {
     898               0 :                 UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[0])),
     899               0 :                              m_poMIFFile->GetYTrans(atof(papszToken[1])));
     900               0 :                 UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[2])),
     901               0 :                              m_poMIFFile->GetYTrans(atof(papszToken[3])));
     902                 :             } 
     903                 :         }
     904                 :         
     905                 :       }
     906                 : 
     907               0 :     CSLDestroy(papszToken);
     908                 :     
     909               0 :     m_poMIFFile->Rewind();
     910                 : 
     911               0 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
     912               0 :       if (EQUALN(pszLine,"DATA",4))
     913               0 :         break;
     914                 : 
     915               0 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
     916                 :     {
     917               0 :         if (m_poMIFFile->IsValidFeature(pszLine))
     918               0 :           break;
     919                 :     }
     920                 : 
     921               0 :     m_poMIDFile->Rewind();
     922               0 :     m_poMIDFile->GetLine();
     923                 :  
     924               0 :     m_bPreParsed = TRUE;
     925                 : 
     926                 : }
     927                 : 
     928                 : /**********************************************************************
     929                 :  *                   MIFFile::WriteMIFHeader()
     930                 :  *
     931                 :  * Generate the .MIF header.
     932                 :  *
     933                 :  * Returns 0 on success, -1 on error.
     934                 :  **********************************************************************/
     935               2 : int MIFFile::WriteMIFHeader()
     936                 : {
     937                 :     int iField;
     938                 :     GBool bFound;
     939                 : 
     940               2 :     if (m_eAccessMode != TABWrite)
     941                 :     {
     942                 :         CPLError(CE_Failure, CPLE_NotSupported,
     943               0 :                  "WriteMIFHeader() can be used only with Write access.");
     944               0 :         return -1;
     945                 :     }
     946                 : 
     947               2 :     if (m_poDefn==NULL || m_poDefn->GetFieldCount() == 0)
     948                 :     {
     949                 :         CPLError(CE_Failure, CPLE_NotSupported,
     950                 :                  "File %s must contain at least 1 attribute field.",
     951               0 :                  m_pszFname);
     952               0 :         return -1;
     953                 :     }
     954                 : 
     955                 :     /*-----------------------------------------------------------------
     956                 :      * Start writing header.
     957                 :      *----------------------------------------------------------------*/
     958               2 :     m_bHeaderWrote = TRUE;
     959               2 :     m_poMIFFile->WriteLine("Version %d\n", m_nVersion);
     960               2 :     m_poMIFFile->WriteLine("Charset \"%s\"\n", m_pszCharset);
     961                 : 
     962                 :     // Delimiter is not required if you use \t as delimiter
     963               2 :     if ( !EQUAL(m_pszDelimiter, "\t") )
     964               2 :         m_poMIFFile->WriteLine("Delimiter \"%s\"\n", m_pszDelimiter);
     965                 : 
     966               2 :     bFound = FALSE;
     967               6 :     for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
     968                 :     {
     969               4 :         if (m_pabFieldUnique[iField])
     970                 :         {
     971               0 :             if (!bFound)
     972               0 :                 m_poMIFFile->WriteLine("Unique %d", iField+1);
     973                 :             else
     974               0 :                 m_poMIFFile->WriteLine(",%d", iField+1);
     975               0 :             bFound = TRUE;
     976                 :         }
     977                 :     }
     978               2 :     if (bFound)
     979               0 :         m_poMIFFile->WriteLine("\n");
     980                 : 
     981               2 :     bFound = FALSE;
     982               6 :     for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
     983                 :     {
     984               4 :         if (m_pabFieldIndexed[iField])
     985                 :         {
     986               0 :             if (!bFound)
     987               0 :                 m_poMIFFile->WriteLine("Index  %d", iField+1);
     988                 :             else
     989               0 :                 m_poMIFFile->WriteLine(",%d", iField+1);
     990               0 :             bFound = TRUE;
     991                 :         }
     992                 :     }
     993               2 :     if (bFound)
     994               0 :         m_poMIFFile->WriteLine("\n");
     995                 : 
     996               2 :     if (m_pszCoordSys && m_bBoundsSet)
     997                 :     {
     998                 :         m_poMIFFile->WriteLine("CoordSys %s "
     999                 :                                "Bounds (%.15g, %.15g) (%.15g, %.15g)\n",
    1000                 :                                m_pszCoordSys, 
    1001               0 :                                m_dXMin, m_dYMin, m_dXMax, m_dYMax);
    1002                 :     }
    1003               2 :     else if (m_pszCoordSys)
    1004                 :     {
    1005               0 :         m_poMIFFile->WriteLine("CoordSys %s\n",m_pszCoordSys);
    1006                 :     }
    1007                 :     
    1008                 :     /*-----------------------------------------------------------------
    1009                 :      * Column definitions
    1010                 :      *----------------------------------------------------------------*/
    1011                 :     CPLAssert(m_paeFieldType);
    1012                 : 
    1013               2 :     m_poMIFFile->WriteLine("Columns %d\n", m_poDefn->GetFieldCount());
    1014                 :         
    1015               6 :     for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
    1016                 :     {
    1017                 :         OGRFieldDefn *poFieldDefn;
    1018               4 :         poFieldDefn = m_poDefn->GetFieldDefn(iField);
    1019                 :         
    1020               4 :         switch(m_paeFieldType[iField])
    1021                 :         {
    1022                 :           case TABFInteger:
    1023                 :             m_poMIFFile->WriteLine("  %s Integer\n",
    1024               2 :                                    poFieldDefn->GetNameRef());
    1025               2 :             break;
    1026                 :           case TABFSmallInt:
    1027                 :             m_poMIFFile->WriteLine("  %s SmallInt\n",
    1028               0 :                                    poFieldDefn->GetNameRef());
    1029               0 :             break;
    1030                 :           case TABFFloat:
    1031                 :             m_poMIFFile->WriteLine("  %s Float\n",
    1032               1 :                                    poFieldDefn->GetNameRef());    
    1033               1 :             break;
    1034                 :           case TABFDecimal:
    1035                 :             m_poMIFFile->WriteLine("  %s Decimal(%d,%d)\n",
    1036                 :                                    poFieldDefn->GetNameRef(),
    1037                 :                                    poFieldDefn->GetWidth(),
    1038               0 :                                    poFieldDefn->GetPrecision());
    1039               0 :             break;
    1040                 :           case TABFLogical:
    1041                 :             m_poMIFFile->WriteLine("  %s Logical\n",
    1042               0 :                                    poFieldDefn->GetNameRef());
    1043               0 :             break;
    1044                 :           case TABFDate:
    1045                 :             m_poMIFFile->WriteLine("  %s Date\n",
    1046               0 :                                    poFieldDefn->GetNameRef());
    1047               0 :             break;
    1048                 :           case TABFTime:
    1049                 :             m_poMIFFile->WriteLine("  %s Time\n",
    1050               0 :                                    poFieldDefn->GetNameRef());
    1051               0 :             break;
    1052                 :           case TABFDateTime:
    1053                 :             m_poMIFFile->WriteLine("  %s DateTime\n",
    1054               0 :                                    poFieldDefn->GetNameRef());
    1055               0 :             break;
    1056                 :           case TABFChar:
    1057                 :           default:
    1058                 :             m_poMIFFile->WriteLine("  %s Char(%d)\n",
    1059                 :                                    poFieldDefn->GetNameRef(),
    1060               1 :                                    poFieldDefn->GetWidth());
    1061                 :         }
    1062                 :     }
    1063                 : 
    1064                 :     /*-----------------------------------------------------------------
    1065                 :      * Ready to write objects
    1066                 :      *----------------------------------------------------------------*/
    1067               2 :     m_poMIFFile->WriteLine("Data\n\n");
    1068                 :    
    1069               2 :     return 0;
    1070                 : }
    1071                 : 
    1072                 : /**********************************************************************
    1073                 :  *                   MIFFile::Close()
    1074                 :  *
    1075                 :  * Close current file, and release all memory used.
    1076                 :  *
    1077                 :  * Returns 0 on success, -1 on error.
    1078                 :  **********************************************************************/
    1079               9 : int MIFFile::Close()
    1080                 : {
    1081                 :     /* flush .mif header if not already written */
    1082               9 :     if ( m_poDefn != NULL && m_bHeaderWrote == FALSE 
    1083                 :          && m_eAccessMode != TABRead )
    1084                 :     {
    1085               0 :         WriteMIFHeader();     
    1086                 :     }
    1087                 : 
    1088               9 :     if (m_poMIDFile)
    1089                 :     {
    1090               9 :         m_poMIDFile->Close();
    1091               9 :         delete m_poMIDFile;
    1092               9 :         m_poMIDFile = NULL;
    1093                 :     }
    1094                 : 
    1095               9 :     if (m_poMIFFile)
    1096                 :     {
    1097               9 :         m_poMIFFile->Close();
    1098               9 :         delete m_poMIFFile;
    1099               9 :         m_poMIFFile = NULL;
    1100                 :     }
    1101                 : 
    1102               9 :     if (m_poCurFeature)
    1103                 :     {
    1104               0 :         delete m_poCurFeature;
    1105               0 :         m_poCurFeature = NULL;
    1106                 :     }
    1107                 : 
    1108                 :     /*-----------------------------------------------------------------
    1109                 :      * Note: we have to check the reference count before deleting 
    1110                 :      * m_poSpatialRef and m_poDefn
    1111                 :      *----------------------------------------------------------------*/
    1112               9 :     if (m_poDefn && m_poDefn->Dereference() == 0)
    1113               8 :         delete m_poDefn;
    1114               9 :     m_poDefn = NULL;
    1115                 :     
    1116               9 :     if (m_poSpatialRef && m_poSpatialRef->Dereference() == 0)
    1117               0 :         delete m_poSpatialRef;
    1118               9 :     m_poSpatialRef = NULL;
    1119                 : 
    1120               9 :     CPLFree(m_pszCoordSys);
    1121               9 :     m_pszCoordSys = NULL;
    1122                 : 
    1123               9 :     CPLFree(m_pszDelimiter);
    1124               9 :     m_pszDelimiter = NULL;
    1125                 : 
    1126               9 :     CPLFree(m_pszFname);
    1127               9 :     m_pszFname = NULL;
    1128                 : 
    1129               9 :     m_nVersion = 0;
    1130                 : 
    1131               9 :     CPLFree(m_pszCharset);
    1132               9 :     m_pszCharset = NULL;
    1133                 : 
    1134               9 :     CPLFree(m_pabFieldIndexed);
    1135               9 :     m_pabFieldIndexed = NULL;
    1136               9 :     CPLFree(m_pabFieldUnique);
    1137               9 :     m_pabFieldUnique = NULL;
    1138                 : 
    1139               9 :     CPLFree( m_pszIndex );
    1140               9 :     m_pszIndex = NULL;
    1141                 : 
    1142               9 :     CPLFree(m_paeFieldType);
    1143               9 :     m_paeFieldType = NULL;
    1144                 : 
    1145               9 :     m_nCurFeatureId = 0;
    1146               9 :     m_nPreloadedId = 0;
    1147               9 :     m_nFeatureCount =0;
    1148                 :    
    1149               9 :     m_bBoundsSet = FALSE;
    1150                 : 
    1151               9 :     return 0;
    1152                 : }
    1153                 : 
    1154                 : /**********************************************************************
    1155                 :  *                   MIFFile::GetNextFeatureId()
    1156                 :  *
    1157                 :  * Returns feature id that follows nPrevId, or -1 if it is the
    1158                 :  * last feature id.  Pass nPrevId=-1 to fetch the first valid feature id.
    1159                 :  **********************************************************************/
    1160              46 : int MIFFile::GetNextFeatureId(int nPrevId)
    1161                 : {
    1162              46 :     if (m_eAccessMode != TABRead)
    1163                 :     {
    1164                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1165               0 :                  "GetNextFeatureId() can be used only with Read access.");
    1166               0 :         return -1;
    1167                 :     }
    1168                 : 
    1169              46 :     if (nPrevId <= 0 && m_poMIFFile->GetLastLine() != NULL)
    1170               8 :         return 1;       // Feature Ids start at 1
    1171              38 :     else if (nPrevId > 0 && m_poMIFFile->GetLastLine() != NULL)
    1172              32 :         return nPrevId + 1;
    1173                 :     else
    1174               6 :         return -1;
    1175                 : 
    1176                 :     return 0;
    1177                 : }
    1178                 : 
    1179                 : /**********************************************************************
    1180                 :  *                   MIFFile::GotoFeature()
    1181                 :  *
    1182                 :  * Private method to move MIF and MID pointers ready to read specified 
    1183                 :  * feature.  Note that Feature Ids start at 1.
    1184                 :  *
    1185                 :  * Returns 0 on success, -1 on error (likely request for invalid feature id)
    1186                 :  **********************************************************************/
    1187              40 : int MIFFile::GotoFeature(int nFeatureId)
    1188                 : {
    1189                 : 
    1190              40 :     if (nFeatureId < 1)
    1191               0 :       return -1;
    1192                 : 
    1193              40 :     if (nFeatureId == m_nPreloadedId) // CorrectPosition
    1194                 :     {
    1195              39 :         return 0;
    1196                 :     }
    1197                 :     else
    1198                 :     {
    1199               1 :         if (nFeatureId < m_nCurFeatureId || m_nCurFeatureId == 0)
    1200               1 :             ResetReading();
    1201                 : 
    1202               2 :         while(m_nPreloadedId < nFeatureId)
    1203                 :         {
    1204               0 :             if (NextFeature() == FALSE)
    1205               0 :               return -1;
    1206                 :         }
    1207                 : 
    1208                 :         CPLAssert(m_nPreloadedId == nFeatureId);
    1209                 : 
    1210               1 :         return 0;
    1211                 :     }
    1212                 : }
    1213                 : 
    1214                 : /**********************************************************************
    1215                 :  *                   MIFFile::NextFeature()
    1216                 :  **********************************************************************/
    1217                 : 
    1218               0 : GBool MIFFile::NextFeature()
    1219                 : {
    1220                 :     const char *pszLine;
    1221               0 :     while ((pszLine = m_poMIFFile->GetLine()) != NULL)
    1222                 :     {
    1223               0 :         if (m_poMIFFile->IsValidFeature(pszLine))
    1224                 :         {
    1225               0 :             m_poMIDFile->GetLine();
    1226               0 :             m_nPreloadedId++;
    1227               0 :             return TRUE;
    1228                 :         }
    1229                 :     }
    1230               0 :     return FALSE;
    1231                 : }
    1232                 : 
    1233                 : /**********************************************************************
    1234                 :  *                   MIFFile::GetFeatureRef()
    1235                 :  *
    1236                 :  * Fill and return a TABFeature object for the specified feature id.
    1237                 :  *
    1238                 :  * The retruned pointer is a reference to an object owned and maintained
    1239                 :  * by this MIFFile object.  It should not be altered or freed by the 
    1240                 :  * caller and its contents is guaranteed to be valid only until the next
    1241                 :  * call to GetFeatureRef() or Close().
    1242                 :  *
    1243                 :  * Returns NULL if the specified feature id does not exist of if an
    1244                 :  * error happened.  In any case, CPLError() will have been called to
    1245                 :  * report the reason of the failure.
    1246                 :  **********************************************************************/
    1247              40 : TABFeature *MIFFile::GetFeatureRef(int nFeatureId)
    1248                 : {
    1249                 :     const char *pszLine;
    1250                 : 
    1251              40 :     if (m_eAccessMode != TABRead)
    1252                 :     {
    1253                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1254               0 :                  "GetFeatureRef() can be used only with Read access.");
    1255               0 :         return NULL;
    1256                 :     }
    1257                 :     
    1258                 :     /*-----------------------------------------------------------------
    1259                 :      * Make sure file is opened and Validate feature id by positioning
    1260                 :      * the read pointers for the .MAP and .DAT files to this feature id.
    1261                 :      *----------------------------------------------------------------*/
    1262              40 :     if (m_poMIDFile == NULL)
    1263                 :     {
    1264                 :         CPLError(CE_Failure, CPLE_IllegalArg,
    1265               0 :                  "GetFeatureRef() failed: file is not opened!");
    1266               0 :         return NULL;
    1267                 :     }
    1268                 : 
    1269              40 :     if (GotoFeature(nFeatureId)!= 0 )
    1270                 :     {
    1271                 :         CPLError(CE_Failure, CPLE_IllegalArg,
    1272                 :                  "GetFeatureRef() failed: invalid feature id %d", 
    1273               0 :                  nFeatureId);
    1274               0 :         return NULL;
    1275                 :     }
    1276                 : 
    1277                 : 
    1278                 :     /*-----------------------------------------------------------------
    1279                 :      * Create new feature object of the right type
    1280                 :      *----------------------------------------------------------------*/
    1281              40 :     if ((pszLine = m_poMIFFile->GetLastLine()) != NULL)
    1282                 :     {
    1283                 :         // Delete previous feature... we'll start we a clean one.
    1284              40 :         if (m_poCurFeature)
    1285               5 :             delete m_poCurFeature;
    1286              40 :         m_poCurFeature = NULL;
    1287                 : 
    1288              40 :         m_nCurFeatureId = m_nPreloadedId;
    1289                 : 
    1290              40 :         if (EQUALN(pszLine,"NONE",4))
    1291                 :         {
    1292              12 :             m_poCurFeature = new TABFeature(m_poDefn);
    1293                 :         }
    1294              28 :         else if (EQUALN(pszLine,"POINT",5))
    1295                 :         {
    1296                 :             // Special case, we need to know two lines to decide the type
    1297                 :             char **papszToken;
    1298               0 :             papszToken = CSLTokenizeString(pszLine);
    1299                 :             
    1300               0 :             if (CSLCount(papszToken) !=3)
    1301                 :             {
    1302               0 :                 CSLDestroy(papszToken);
    1303                 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1304                 :                          "GetFeatureRef() failed: invalid point line: '%s'",
    1305               0 :                          pszLine);
    1306               0 :                 return NULL;
    1307                 :             }
    1308                 :             
    1309               0 :             m_poMIFFile->SaveLine(pszLine);
    1310                 : 
    1311               0 :             if ((pszLine = m_poMIFFile->GetLine()) != NULL)
    1312                 :             {
    1313               0 :                 CSLDestroy(papszToken);
    1314                 :                 papszToken = CSLTokenizeStringComplex(pszLine," ,()\t",
    1315               0 :                                                       TRUE,FALSE);
    1316               0 :                 if (CSLCount(papszToken)> 0 &&EQUALN(papszToken[0],"SYMBOL",6))
    1317                 :                 {
    1318               0 :                     switch (CSLCount(papszToken))
    1319                 :                     {
    1320                 :                       case 4:
    1321               0 :                         m_poCurFeature = new TABPoint(m_poDefn);
    1322               0 :                         break;
    1323                 :                       case 7:
    1324               0 :                         m_poCurFeature = new TABFontPoint(m_poDefn);
    1325               0 :                         break;
    1326                 :                       case 5:
    1327               0 :                         m_poCurFeature = new TABCustomPoint(m_poDefn);
    1328               0 :                         break;
    1329                 :                       default:
    1330               0 :                         CSLDestroy(papszToken);
    1331                 :                         CPLError(CE_Failure, CPLE_NotSupported,
    1332                 :                                  "GetFeatureRef() failed: invalid symbol "
    1333               0 :                                  "line: '%s'", pszLine);
    1334               0 :                         return NULL;
    1335                 :                         break;
    1336                 :                     }
    1337                 : 
    1338                 :                 }
    1339                 :             }
    1340               0 :             CSLDestroy(papszToken);
    1341                 : 
    1342               0 :             if (m_poCurFeature == NULL)
    1343                 :             {
    1344                 :                 // No symbol clause... default to TABPoint
    1345               0 :                 m_poCurFeature = new TABPoint(m_poDefn);
    1346                 :             }
    1347                 :         }
    1348              28 :         else if (EQUALN(pszLine,"LINE",4) ||
    1349                 :                  EQUALN(pszLine,"PLINE",5))
    1350                 :         {
    1351               0 :             m_poCurFeature = new TABPolyline(m_poDefn);
    1352                 :         }
    1353              28 :         else if (EQUALN(pszLine,"REGION",6))
    1354                 :         {
    1355              28 :             m_poCurFeature = new TABRegion(m_poDefn);
    1356                 :         }  
    1357               0 :         else if (EQUALN(pszLine,"ARC",3))
    1358                 :         { 
    1359               0 :             m_poCurFeature = new TABArc(m_poDefn);
    1360                 :         }
    1361               0 :         else if (EQUALN(pszLine,"TEXT",4))
    1362                 :         {
    1363               0 :             m_poCurFeature = new TABText(m_poDefn);
    1364                 :         }
    1365               0 :         else if (EQUALN(pszLine,"RECT",4) ||
    1366                 :                  EQUALN(pszLine,"ROUNDRECT",9))
    1367                 :         {
    1368               0 :             m_poCurFeature = new TABRectangle(m_poDefn);
    1369                 :         }
    1370               0 :         else if (EQUALN(pszLine,"ELLIPSE",7))
    1371                 :         {
    1372               0 :             m_poCurFeature = new TABEllipse(m_poDefn);       
    1373                 :         }
    1374               0 :         else if (EQUALN(pszLine,"MULTIPOINT",10))
    1375                 :         {
    1376               0 :             m_poCurFeature = new TABMultiPoint(m_poDefn);       
    1377                 :         }
    1378               0 :         else if (EQUALN(pszLine,"COLLECTION",10))
    1379                 :         {
    1380               0 :             m_poCurFeature = new TABCollection(m_poDefn);       
    1381                 :         }
    1382                 :         else
    1383                 :         {
    1384               0 :             if (!EQUAL(pszLine,""))
    1385                 :                CPLError(CE_Failure, CPLE_NotSupported,
    1386                 :                    "Error during reading, unknown type %s.",
    1387               0 :                      pszLine);
    1388                 :         
    1389                 :             //m_poCurFeature = new TABDebugFeature(m_poDefn);
    1390               0 :             return NULL;
    1391                 :         }
    1392                 :     }
    1393                 : 
    1394                 :     CPLAssert(m_poCurFeature);
    1395              40 :     if (m_poCurFeature == NULL)
    1396               0 :         return NULL;
    1397                 : 
    1398                 :    /*-----------------------------------------------------------------
    1399                 :      * Read fields from the .DAT file
    1400                 :      * GetRecordBlock() has already been called above...
    1401                 :      *----------------------------------------------------------------*/
    1402              40 :     if (m_poCurFeature->ReadRecordFromMIDFile(m_poMIDFile) != 0)
    1403                 :     {
    1404                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1405               0 :                  "Error during reading Record.");
    1406                 :         
    1407               0 :         delete m_poCurFeature;
    1408               0 :         m_poCurFeature = NULL;
    1409               0 :         return NULL;
    1410                 :     }
    1411                 :     
    1412                 :     /*-----------------------------------------------------------------
    1413                 :      * Read geometry from the .MAP file
    1414                 :      * MoveToObjId() has already been called above...
    1415                 :      *----------------------------------------------------------------*/
    1416              40 :     if (m_poCurFeature->ReadGeometryFromMIFFile(m_poMIFFile) != 0)
    1417                 :     {
    1418                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1419               0 :                  "Error during reading Geometry.");
    1420                 :         
    1421               0 :         delete m_poCurFeature;
    1422               0 :         m_poCurFeature = NULL;
    1423               0 :         return NULL;
    1424                 :     }
    1425                 : 
    1426                 :     /*---------------------------------------------------------------------
    1427                 :      * The act of reading the geometry causes the first line of the    
    1428                 :      * next object to be preloaded.  Set the preloaded id appropriately.
    1429                 :      *--------------------------------------------------------------------- */
    1430              40 :     if( m_poMIFFile->GetLastLine() != NULL )
    1431              32 :         m_nPreloadedId++;
    1432                 :     else
    1433               8 :         m_nPreloadedId = 0;
    1434                 :    
    1435                 :     /* Update the Current Feature ID */
    1436              40 :     m_poCurFeature->SetFID(m_nCurFeatureId);
    1437                 : 
    1438              40 :     return m_poCurFeature;
    1439                 : }
    1440                 : 
    1441                 : /**********************************************************************
    1442                 :  *                   MIFFile::CreateFeature()
    1443                 :  *
    1444                 :  * Write a new feature to this dataset. The passed in feature is updated 
    1445                 :  * with the new feature id.
    1446                 :  *
    1447                 :  * Returns OGRERR_NONE on success, or an appropriate OGRERR_ code if an
    1448                 :  * error happened in which case, CPLError() will have been called to
    1449                 :  * report the reason of the failure.
    1450                 :  **********************************************************************/
    1451              16 : OGRErr MIFFile::CreateFeature(TABFeature *poFeature)
    1452                 : {
    1453              16 :     int nFeatureId = -1;
    1454                 : 
    1455              16 :     if (m_eAccessMode != TABWrite)
    1456                 :     {
    1457                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1458               0 :                  "CreateFeature() can be used only with Write access.");
    1459               0 :         return OGRERR_UNSUPPORTED_OPERATION;
    1460                 :     }
    1461                 : 
    1462                 :     /*-----------------------------------------------------------------
    1463                 :      * Make sure file is opened and establish new feature id.
    1464                 :      *----------------------------------------------------------------*/
    1465              16 :     if (m_poMIDFile == NULL)
    1466                 :     {
    1467                 :         CPLError(CE_Failure, CPLE_IllegalArg,
    1468               0 :                  "CreateFeature() failed: file is not opened!");
    1469               0 :         return OGRERR_FAILURE;
    1470                 :     }
    1471                 : 
    1472              16 :     if (m_bHeaderWrote == FALSE)
    1473                 :     {
    1474                 :         /*-------------------------------------------------------------
    1475                 :          * OK, this is the first feature in the dataset... make sure the
    1476                 :          * .MID schema has been initialized.
    1477                 :          *------------------------------------------------------------*/
    1478               2 :         if (m_poDefn == NULL)
    1479               0 :             SetFeatureDefn(poFeature->GetDefnRef(), NULL);
    1480                 : 
    1481               2 :          WriteMIFHeader();     
    1482               2 :          nFeatureId = 1;
    1483                 :     }
    1484                 :     else
    1485                 :     {
    1486              14 :         nFeatureId = ++ m_nWriteFeatureId;
    1487                 :     }
    1488                 : 
    1489                 : 
    1490                 :     /*-----------------------------------------------------------------
    1491                 :      * Write geometry to the .Mif file
    1492                 :      *----------------------------------------------------------------*/
    1493              32 :     if (m_poMIFFile == NULL ||
    1494              16 :         poFeature->WriteGeometryToMIFFile(m_poMIFFile) != 0)
    1495                 :     {
    1496                 :         CPLError(CE_Failure, CPLE_FileIO,
    1497                 :                  "Failed writing geometry for feature id %d in %s",
    1498               0 :                  nFeatureId, m_pszFname);
    1499               0 :         return OGRERR_FAILURE;
    1500                 :     }
    1501                 : 
    1502              32 :     if (m_poMIDFile == NULL ||
    1503              16 :         poFeature->WriteRecordToMIDFile(m_poMIDFile) != 0 )
    1504                 :     {
    1505                 :         CPLError(CE_Failure, CPLE_FileIO,
    1506                 :                  "Failed writing attributes for feature id %d in %s",
    1507               0 :                  nFeatureId, m_pszFname);
    1508               0 :         return OGRERR_FAILURE;
    1509                 :     }
    1510                 : 
    1511              16 :     poFeature->SetFID(nFeatureId);
    1512                 : 
    1513              16 :     return OGRERR_NONE;
    1514                 : }
    1515                 : 
    1516                 : 
    1517                 : 
    1518                 : /**********************************************************************
    1519                 :  *                   MIFFile::GetLayerDefn()
    1520                 :  *
    1521                 :  * Returns a reference to the OGRFeatureDefn that will be used to create
    1522                 :  * features in this dataset.
    1523                 :  *
    1524                 :  * Returns a reference to an object that is maintained by this MIFFile
    1525                 :  * object (and thus should not be modified or freed by the caller) or
    1526                 :  * NULL if the OGRFeatureDefn has not been initialized yet (i.e. no file
    1527                 :  * opened yet)
    1528                 :  **********************************************************************/
    1529             116 : OGRFeatureDefn *MIFFile::GetLayerDefn()
    1530                 : {
    1531             116 :     return m_poDefn;
    1532                 : }
    1533                 : 
    1534                 : /**********************************************************************
    1535                 :  *                   MIFFile::SetFeatureDefn()
    1536                 :  *
    1537                 :  * Pass a reference to the OGRFeatureDefn that will be used to create
    1538                 :  * features in this dataset.  This function should be called after
    1539                 :  * creating a new dataset, but before writing the first feature.
    1540                 :  * All features that will be written to this dataset must share this same
    1541                 :  * OGRFeatureDefn.
    1542                 :  *
    1543                 :  * This function will use poFeatureDefn to create a local copy that 
    1544                 :  * will be used to build the .MID file, etc.
    1545                 :  *
    1546                 :  * Returns 0 on success, -1 on error.
    1547                 :  **********************************************************************/
    1548               0 : int MIFFile::SetFeatureDefn(OGRFeatureDefn *poFeatureDefn,
    1549                 :                          TABFieldType *paeMapInfoNativeFieldTypes /* =NULL */)
    1550                 : {
    1551                 :     int numFields;
    1552               0 :     int nStatus = 0;
    1553                 : 
    1554                 :     /*-----------------------------------------------------------------
    1555                 :      * Check that call happens at the right time in dataset's life.
    1556                 :      *----------------------------------------------------------------*/
    1557               0 :     if ( m_eAccessMode == TABWrite && m_bHeaderWrote )
    1558                 :     {
    1559                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1560                 :                  "SetFeatureDefn() must be called after opening a new "
    1561               0 :                  "dataset, but before writing the first feature to it.");
    1562               0 :         return -1;
    1563                 :     }
    1564                 : 
    1565                 :     /*-----------------------------------------------------------------
    1566                 :      * Delete current feature defn if there is already one.
    1567                 :      * AddFieldNative() will take care of creating a new one for us.
    1568                 :      *----------------------------------------------------------------*/
    1569               0 :     if (m_poDefn && m_poDefn->Dereference() == 0)
    1570               0 :         delete m_poDefn;
    1571               0 :     m_poDefn = NULL;
    1572                 : 
    1573                 :     /*-----------------------------------------------------------------
    1574                 :      * Copy field information
    1575                 :      *----------------------------------------------------------------*/
    1576               0 :     numFields = poFeatureDefn->GetFieldCount();
    1577                 : 
    1578               0 :     for(int iField=0; iField<numFields; iField++)
    1579                 :     {
    1580                 :         TABFieldType eMapInfoType;
    1581               0 :         OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
    1582                 : 
    1583               0 :         if (paeMapInfoNativeFieldTypes)
    1584                 :         {
    1585               0 :             eMapInfoType = paeMapInfoNativeFieldTypes[iField];
    1586                 :         }
    1587                 :         else
    1588                 :         {
    1589                 :             /*---------------------------------------------------------
    1590                 :              * Map OGRFieldTypes to MapInfo native types
    1591                 :              *--------------------------------------------------------*/
    1592               0 :             switch(poFieldDefn->GetType())
    1593                 :             {
    1594                 :               case OFTInteger:
    1595               0 :                 eMapInfoType = TABFInteger;
    1596               0 :                 break;
    1597                 :               case OFTReal:
    1598               0 :                 eMapInfoType = TABFFloat;
    1599               0 :                 break;
    1600                 :               case OFTDateTime:
    1601               0 :                 eMapInfoType = TABFDateTime;
    1602               0 :                 break;
    1603                 :               case OFTDate:
    1604               0 :                 eMapInfoType = TABFDate;
    1605               0 :                 break;
    1606                 :               case OFTTime:
    1607               0 :                 eMapInfoType = TABFTime;
    1608               0 :                 break;
    1609                 :               case OFTString:
    1610                 :               default:
    1611               0 :                 eMapInfoType = TABFChar;
    1612                 :             }
    1613                 :         }
    1614                 : 
    1615                 :         nStatus = AddFieldNative(poFieldDefn->GetNameRef(), eMapInfoType,
    1616                 :                                  poFieldDefn->GetWidth(),
    1617               0 :                                  poFieldDefn->GetPrecision(), FALSE, FALSE);
    1618                 :     }
    1619                 : 
    1620               0 :     return nStatus;
    1621                 : }
    1622                 : 
    1623                 : /**********************************************************************
    1624                 :  *                   MIFFile::AddFieldNative()
    1625                 :  *
    1626                 :  * Create a new field using a native mapinfo data type... this is an 
    1627                 :  * alternative to defining fields through the OGR interface.
    1628                 :  * This function should be called after creating a new dataset, but before 
    1629                 :  * writing the first feature.
    1630                 :  *
    1631                 :  * This function will build/update the OGRFeatureDefn that will have to be
    1632                 :  * used when writing features to this dataset.
    1633                 :  *
    1634                 :  * A reference to the OGRFeatureDefn can be obtained using GetLayerDefn().
    1635                 :  *
    1636                 :  * Returns 0 on success, -1 on error.
    1637                 :  **********************************************************************/
    1638              43 : int MIFFile::AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
    1639                 :                             int nWidth /*=0*/, int nPrecision /*=0*/,
    1640                 :                             GBool bIndexed /*=FALSE*/, GBool bUnique/*=FALSE*/)
    1641                 : {
    1642                 :     OGRFieldDefn *poFieldDefn;
    1643              43 :     char *pszCleanName = NULL;
    1644              43 :     int nStatus = 0;
    1645                 : 
    1646                 :     /*-----------------------------------------------------------------
    1647                 :      * Check that call happens at the right time in dataset's life.
    1648                 :      *----------------------------------------------------------------*/
    1649              43 :     if ( m_eAccessMode == TABWrite && m_bHeaderWrote )
    1650                 :     {
    1651                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1652                 :                  "AddFieldNative() must be called after opening a new "
    1653               0 :                  "dataset, but before writing the first feature to it.");
    1654               0 :         return -1;
    1655                 :     }
    1656                 : 
    1657                 :     /*-----------------------------------------------------------------
    1658                 :      * Validate field width... must be <= 254
    1659                 :      *----------------------------------------------------------------*/
    1660              43 :     if (nWidth > 254)
    1661                 :     {
    1662                 :         CPLError(CE_Warning, CPLE_IllegalArg,
    1663                 :                  "Invalid size (%d) for field '%s'.  "
    1664               0 :                  "Size must be 254 or less.", nWidth, pszName);
    1665               0 :         nWidth = 254;
    1666                 :     }
    1667                 : 
    1668                 :     /*-----------------------------------------------------------------
    1669                 :      * Map fields with width=0 (variable length in OGR) to a valid default
    1670                 :      *----------------------------------------------------------------*/
    1671              43 :     if (eMapInfoType == TABFDecimal && nWidth == 0)
    1672               0 :         nWidth=20;
    1673              43 :     else if (nWidth == 0)
    1674              23 :         nWidth=254; /* char fields */
    1675                 : 
    1676                 :     /*-----------------------------------------------------------------
    1677                 :      * Create new OGRFeatureDefn if not done yet...
    1678                 :      *----------------------------------------------------------------*/
    1679              43 :     if (m_poDefn == NULL)
    1680                 :     {
    1681               2 :         char *pszFeatureClassName = TABGetBasename(m_pszFname);
    1682               2 :         m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
    1683               2 :         CPLFree(pszFeatureClassName);
    1684                 :         // Ref count defaults to 0... set it to 1
    1685               2 :         m_poDefn->Reference();
    1686                 :     }
    1687                 : 
    1688                 :     /*-----------------------------------------------------------------
    1689                 :      * Make sure field name is valid... check for special chars, etc.
    1690                 :      * (pszCleanName will have to be freed.)
    1691                 :      *----------------------------------------------------------------*/
    1692              43 :     pszCleanName = TABCleanFieldName(pszName);
    1693                 : 
    1694                 :     /*-----------------------------------------------------------------
    1695                 :      * Map MapInfo native types to OGR types
    1696                 :      *----------------------------------------------------------------*/
    1697              43 :     poFieldDefn = NULL;
    1698                 : 
    1699              43 :     switch(eMapInfoType)
    1700                 :     {
    1701                 :       case TABFChar:
    1702                 :         /*-------------------------------------------------
    1703                 :          * CHAR type
    1704                 :          *------------------------------------------------*/
    1705              17 :         poFieldDefn = new OGRFieldDefn(pszCleanName, OFTString);
    1706              17 :         poFieldDefn->SetWidth(nWidth);
    1707              17 :         break;
    1708                 :       case TABFInteger:
    1709                 :         /*-------------------------------------------------
    1710                 :          * INTEGER type
    1711                 :          *------------------------------------------------*/
    1712              14 :         poFieldDefn = new OGRFieldDefn(pszCleanName, OFTInteger);
    1713              14 :         break;
    1714                 :       case TABFSmallInt:
    1715                 :         /*-------------------------------------------------
    1716                 :          * SMALLINT type
    1717                 :          *------------------------------------------------*/
    1718               0 :         poFieldDefn = new OGRFieldDefn(pszCleanName, OFTInteger);
    1719               0 :         break;
    1720                 :       case TABFDecimal:
    1721                 :         /*-------------------------------------------------
    1722                 :          * DECIMAL type
    1723                 :          *------------------------------------------------*/
    1724               0 :         poFieldDefn = new OGRFieldDefn(pszCleanName, OFTReal);
    1725               0 :         poFieldDefn->SetWidth(nWidth);
    1726               0 :         poFieldDefn->SetPrecision(nPrecision);
    1727               0 :         break;
    1728                 :       case TABFFloat:
    1729                 :         /*-------------------------------------------------
    1730                 :          * FLOAT type
    1731                 :          *------------------------------------------------*/
    1732              12 :         poFieldDefn = new OGRFieldDefn(pszCleanName, OFTReal);
    1733              12 :         break;
    1734                 :       case TABFDate:
    1735                 :         /*-------------------------------------------------
    1736                 :          * DATE type (V450, returned as a string: "DD/MM/YYYY" or "YYYYMMDD")
    1737                 :          *------------------------------------------------*/
    1738                 :         poFieldDefn = new OGRFieldDefn(pszCleanName, 
    1739                 : #ifdef MITAB_USE_OFTDATETIME
    1740               0 :                                                    OFTDate);
    1741                 : #else
    1742                 :                                                    OFTString);
    1743                 : #endif
    1744               0 :         poFieldDefn->SetWidth(10);
    1745               0 :         m_nVersion = MAX(m_nVersion, 450);
    1746               0 :         break;
    1747                 :       case TABFTime:
    1748                 :         /*-------------------------------------------------
    1749                 :          * TIME type (v900, returned as a string: "HH:MM:SS" or "HHMMSSmmm")
    1750                 :          *------------------------------------------------*/
    1751                 :         poFieldDefn = new OGRFieldDefn(pszCleanName, 
    1752                 : #ifdef MITAB_USE_OFTDATETIME
    1753               0 :                                                    OFTTime);
    1754                 : #else
    1755                 :                                                    OFTString);
    1756                 : #endif
    1757               0 :         poFieldDefn->SetWidth(9);
    1758               0 :         m_nVersion = MAX(m_nVersion, 900);
    1759               0 :         break;
    1760                 :       case TABFDateTime:
    1761                 :         /*-------------------------------------------------
    1762                 :          * DATETIME type (v900, returned as a string: "DD/MM/YYYY HH:MM:SS",
    1763                 :          * "YYYY/MM/DD HH:MM:SS" or "YYYYMMDDHHMMSSmmm")
    1764                 :          *------------------------------------------------*/
    1765                 :         poFieldDefn = new OGRFieldDefn(pszCleanName, 
    1766                 : #ifdef MITAB_USE_OFTDATETIME
    1767               0 :                                                    OFTDateTime);
    1768                 : #else
    1769                 :                                                    OFTString);
    1770                 : #endif
    1771               0 :         poFieldDefn->SetWidth(19);
    1772               0 :         break;
    1773                 :         m_nVersion = MAX(m_nVersion, 900);
    1774                 :       case TABFLogical:
    1775                 :         /*-------------------------------------------------
    1776                 :          * LOGICAL type (value "T" or "F")
    1777                 :          *------------------------------------------------*/
    1778               0 :         poFieldDefn = new OGRFieldDefn(pszCleanName, OFTString);
    1779               0 :         poFieldDefn->SetWidth(1);
    1780               0 :         break;
    1781                 :       default:
    1782                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1783               0 :                  "Unsupported type for field %s", pszName);
    1784               0 :         return -1;
    1785                 :     }
    1786                 : 
    1787                 :     /*-----------------------------------------------------
    1788                 :      * Add the FieldDefn to the FeatureDefn 
    1789                 :      *----------------------------------------------------*/
    1790              43 :     m_poDefn->AddFieldDefn(poFieldDefn);
    1791              43 :     delete poFieldDefn;
    1792                 : 
    1793                 :     /*-----------------------------------------------------------------
    1794                 :      * Keep track of native field type
    1795                 :      *----------------------------------------------------------------*/
    1796                 :     m_paeFieldType = (TABFieldType *)CPLRealloc(m_paeFieldType,
    1797                 :                                                 m_poDefn->GetFieldCount()*
    1798              43 :                                                 sizeof(TABFieldType));
    1799              43 :     m_paeFieldType[m_poDefn->GetFieldCount()-1] = eMapInfoType;
    1800                 : 
    1801                 :     /*-----------------------------------------------------------------
    1802                 :      * Extend array of Indexed/Unique flags
    1803                 :      *----------------------------------------------------------------*/
    1804                 :     m_pabFieldIndexed = (GBool *)CPLRealloc(m_pabFieldIndexed,
    1805                 :                                             m_poDefn->GetFieldCount()*
    1806              43 :                                             sizeof(GBool));
    1807                 :     m_pabFieldUnique  = (GBool *)CPLRealloc(m_pabFieldUnique,
    1808                 :                                             m_poDefn->GetFieldCount()*
    1809              43 :                                             sizeof(GBool));
    1810              43 :     m_pabFieldIndexed[m_poDefn->GetFieldCount()-1] = bIndexed;
    1811              43 :     m_pabFieldUnique[m_poDefn->GetFieldCount()-1] = bUnique;
    1812                 : 
    1813              43 :     CPLFree(pszCleanName);
    1814              43 :     return nStatus;
    1815                 : }
    1816                 : 
    1817                 : 
    1818                 : /**********************************************************************
    1819                 :  *                   MIFFile::GetNativeFieldType()
    1820                 :  *
    1821                 :  * Returns the native MapInfo field type for the specified field.
    1822                 :  *
    1823                 :  * Returns TABFUnknown if file is not opened, or if specified field index is
    1824                 :  * invalid.
    1825                 :  **********************************************************************/
    1826               0 : TABFieldType MIFFile::GetNativeFieldType(int nFieldId)
    1827                 : {
    1828               0 :     if ( m_poDefn==NULL || m_paeFieldType==NULL ||
    1829                 :          nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
    1830               0 :         return TABFUnknown;
    1831                 : 
    1832               0 :     return m_paeFieldType[nFieldId];
    1833                 : }
    1834                 : 
    1835                 : /************************************************************************
    1836                 :  *                       MIFFile::SetFieldIndexed()
    1837                 :  ************************************************************************/
    1838                 : 
    1839               0 : int MIFFile::SetFieldIndexed( int nFieldId )
    1840                 : 
    1841                 : {
    1842               0 :     if ( m_poDefn==NULL || m_pabFieldIndexed==NULL ||
    1843                 :          nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
    1844               0 :         return -1;
    1845                 : 
    1846               0 :     m_pabFieldIndexed[nFieldId] = TRUE;
    1847                 : 
    1848               0 :     return 0;
    1849                 : }
    1850                 : 
    1851                 : /************************************************************************
    1852                 :  *                       MIFFile::IsFieldIndexed()
    1853                 :  ************************************************************************/
    1854                 : 
    1855               0 : GBool MIFFile::IsFieldIndexed( int nFieldId )
    1856                 : 
    1857                 : {
    1858               0 :     if ( m_poDefn==NULL || m_pabFieldIndexed==NULL ||
    1859                 :          nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
    1860               0 :         return FALSE;
    1861                 : 
    1862               0 :     return m_pabFieldIndexed[nFieldId];
    1863                 : }
    1864                 : 
    1865                 : /************************************************************************
    1866                 :  *                       MIFFile::IsFieldUnique()
    1867                 :  ************************************************************************/
    1868                 : 
    1869               0 : GBool MIFFile::IsFieldUnique( int nFieldId )
    1870                 : 
    1871                 : {
    1872               0 :     if ( m_poDefn==NULL || m_pabFieldUnique==NULL ||
    1873                 :          nFieldId < 0 || nFieldId >= m_poDefn->GetFieldCount())
    1874               0 :         return FALSE;
    1875                 : 
    1876               0 :     return m_pabFieldUnique[nFieldId];
    1877                 : }
    1878                 : 
    1879                 : 
    1880                 : /************************************************************************/
    1881                 : /*                       MIFFile::SetSpatialRef()                       */
    1882                 : /************************************************************************/
    1883                 : 
    1884               0 : int MIFFile::SetSpatialRef( OGRSpatialReference * poSpatialRef )
    1885                 : 
    1886                 : {
    1887               0 :     CPLFree( m_pszCoordSys );
    1888                 : 
    1889               0 :     m_pszCoordSys = MITABSpatialRef2CoordSys( poSpatialRef );
    1890                 : 
    1891               0 :     return( m_pszCoordSys != NULL );
    1892                 : }
    1893                 : 
    1894                 : 
    1895                 : /************************************************************************/
    1896                 : /*                      MIFFile::SetMIFCoordSys()                       */
    1897                 : /************************************************************************/
    1898                 : 
    1899               0 : int MIFFile::SetMIFCoordSys(const char * pszMIFCoordSys)
    1900                 : 
    1901                 : {
    1902                 :     char        **papszFields, *pszCoordSys;
    1903                 :     int         iBounds;
    1904                 : 
    1905                 :     // Extract the word 'COORDSYS' if present
    1906               0 :     if (EQUALN(pszMIFCoordSys,"COORDSYS",8) )
    1907                 :     {
    1908               0 :         pszCoordSys = CPLStrdup(pszMIFCoordSys + 9);
    1909                 :     }
    1910                 :     else
    1911                 :     {
    1912               0 :         pszCoordSys = CPLStrdup(pszMIFCoordSys);
    1913                 :     }
    1914                 : 
    1915                 :     // Extract bounds if present
    1916                 :     papszFields = CSLTokenizeStringComplex(pszCoordSys, " ,()\t",
    1917               0 :                                            TRUE, FALSE );
    1918               0 :     iBounds = CSLFindString( papszFields, "Bounds" );
    1919               0 :     if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
    1920                 :     {
    1921               0 :         m_dXMin = atof(papszFields[++iBounds]);
    1922               0 :         m_dYMin = atof(papszFields[++iBounds]);
    1923               0 :         m_dXMax = atof(papszFields[++iBounds]);
    1924               0 :         m_dYMax = atof(papszFields[++iBounds]);
    1925               0 :         m_bBoundsSet = TRUE;
    1926                 : 
    1927               0 :         pszCoordSys[strstr(pszCoordSys, "Bounds") - pszCoordSys] = '\0';
    1928                 :     }
    1929               0 :     CSLDestroy( papszFields );
    1930                 : 
    1931                 :     // Assign the CoordSys
    1932               0 :     CPLFree( m_pszCoordSys );
    1933                 : 
    1934               0 :     m_pszCoordSys = CPLStrdup(pszCoordSys);
    1935               0 :     CPLFree(pszCoordSys);
    1936                 : 
    1937               0 :     return( m_pszCoordSys != NULL );
    1938                 : }
    1939                 : 
    1940                 : /************************************************************************/
    1941                 : /*                       MIFFile::GetSpatialRef()                       */
    1942                 : /************************************************************************/
    1943                 : 
    1944               1 : OGRSpatialReference *MIFFile::GetSpatialRef()
    1945                 : 
    1946                 : {
    1947               1 :     if( m_poSpatialRef == NULL )
    1948               1 :         m_poSpatialRef = MITABCoordSys2SpatialRef( m_pszCoordSys );
    1949                 : 
    1950               1 :     return m_poSpatialRef;
    1951                 : }
    1952                 : 
    1953                 : /**********************************************************************
    1954                 :  *                   MIFFile::UpdateExtents()
    1955                 :  *
    1956                 :  * Private Methode used to update the dataset extents
    1957                 :  **********************************************************************/
    1958               0 : void MIFFile::UpdateExtents(double dfX, double dfY)
    1959                 : {
    1960               0 :     if (m_bExtentsSet == FALSE)
    1961                 :     {
    1962               0 :         m_bExtentsSet = TRUE;
    1963               0 :         m_sExtents.MinX = m_sExtents.MaxX = dfX;
    1964               0 :         m_sExtents.MinY = m_sExtents.MaxY = dfY;
    1965                 :     }
    1966                 :     else
    1967                 :     {
    1968               0 :         if (dfX < m_sExtents.MinX)
    1969               0 :             m_sExtents.MinX = dfX;
    1970               0 :         if (dfX > m_sExtents.MaxX)
    1971               0 :           m_sExtents.MaxX = dfX;
    1972               0 :         if (dfY < m_sExtents.MinY)
    1973               0 :           m_sExtents.MinY = dfY;
    1974               0 :         if (dfY > m_sExtents.MaxY)
    1975               0 :           m_sExtents.MaxY = dfY;
    1976                 :     }
    1977               0 : }
    1978                 : 
    1979                 : /**********************************************************************
    1980                 :  *                   MIFFile::SetBounds()
    1981                 :  *
    1982                 :  * Set projection coordinates bounds of the newly created dataset.
    1983                 :  *
    1984                 :  * This function must be called after creating a new dataset and before any
    1985                 :  * feature can be written to it.
    1986                 :  *
    1987                 :  * Returns 0 on success, -1 on error.
    1988                 :  **********************************************************************/
    1989               0 : int MIFFile::SetBounds(double dXMin, double dYMin, 
    1990                 :                        double dXMax, double dYMax)
    1991                 : {
    1992               0 :     if (m_eAccessMode != TABWrite)
    1993                 :     {
    1994                 :         CPLError(CE_Failure, CPLE_NotSupported,
    1995               0 :                  "SetBounds() can be used only with Write access.");
    1996               0 :         return -1;
    1997                 :     }
    1998                 : 
    1999               0 :     m_dXMin = dXMin;
    2000               0 :     m_dXMax = dXMax;
    2001               0 :     m_dYMin = dYMin;
    2002               0 :     m_dYMax = dYMax;
    2003               0 :     m_bBoundsSet = TRUE;
    2004                 :     
    2005               0 :     return 0; 
    2006                 : }
    2007                 : 
    2008                 : 
    2009                 : /**********************************************************************
    2010                 :  *                   MIFFile::GetFeatureCountByType()
    2011                 :  *
    2012                 :  * Return number of features of each type.
    2013                 :  *
    2014                 :  * NOTE: The current implementation always returns -1 for MIF files
    2015                 :  *       since this would require scanning the whole file.
    2016                 :  *
    2017                 :  * When properly implemented, the bForce flag will force scanning the
    2018                 :  * whole file by default.
    2019                 :  *
    2020                 :  * Returns 0 on success, or silently returns -1 (with no error) if this
    2021                 :  * information is not available.
    2022                 :  **********************************************************************/
    2023               9 : int MIFFile::GetFeatureCountByType(int &numPoints, int &numLines,
    2024                 :                                    int &numRegions, int &numTexts,
    2025                 :                                    GBool bForce )
    2026                 : {
    2027               9 :     if( m_bPreParsed || bForce )
    2028                 :     {
    2029               0 :         PreParseFile();
    2030                 : 
    2031               0 :         numPoints = m_nPoints;
    2032               0 :         numLines = m_nLines;
    2033               0 :         numRegions = m_nRegions;
    2034               0 :         numTexts = m_nTexts;
    2035               0 :         return 0;
    2036                 :     }
    2037                 :     else
    2038                 :     {
    2039               9 :         numPoints = numLines = numRegions = numTexts = 0;
    2040               9 :         return -1;
    2041                 :     }
    2042                 : }
    2043                 : 
    2044                 : /**********************************************************************
    2045                 :  *                   MIFFile::GetBounds()
    2046                 :  *
    2047                 :  * Fetch projection coordinates bounds of a dataset.
    2048                 :  *
    2049                 :  * Pass bForce=FALSE to avoid a scan of the whole file if the bounds
    2050                 :  * are not already available.
    2051                 :  *
    2052                 :  * Returns 0 on success, -1 on error or if bounds are not available and
    2053                 :  * bForce=FALSE.
    2054                 :  **********************************************************************/
    2055               0 : int MIFFile::GetBounds(double &dXMin, double &dYMin, 
    2056                 :                        double &dXMax, double &dYMax,
    2057                 :                        GBool bForce /*= TRUE*/ )
    2058                 : {
    2059                 :     
    2060               0 :     if (m_bBoundsSet == FALSE && bForce == FALSE)
    2061                 :     {
    2062               0 :         return -1;
    2063                 :     }
    2064               0 :     else if (m_bBoundsSet == FALSE)
    2065                 :     {
    2066               0 :         PreParseFile();
    2067                 :     }
    2068                 : 
    2069               0 :     if (m_bBoundsSet == FALSE)
    2070                 :     {
    2071               0 :         return -1;
    2072                 :     }
    2073                 : 
    2074               0 :     dXMin = m_dXMin;
    2075               0 :     dXMax = m_dXMax;
    2076               0 :     dYMin = m_dYMin;
    2077               0 :     dYMax = m_dYMax;
    2078                 :     
    2079               0 :     return 0;
    2080                 : }
    2081                 : 
    2082                 : /**********************************************************************
    2083                 :  *                   MIFFile::GetExtent()
    2084                 :  *
    2085                 :  * Fetch extent of the data currently stored in the dataset.  We collect
    2086                 :  * this information while preparsing the file ... often already done for
    2087                 :  * other reasons, and if not it is still faster than fully reading all
    2088                 :  * the features just to count them.
    2089                 :  *
    2090                 :  * Returns OGRERR_NONE/OGRRERR_FAILURE.
    2091                 :  **********************************************************************/
    2092               0 : OGRErr MIFFile::GetExtent (OGREnvelope *psExtent, int bForce)
    2093                 : {
    2094               0 :     if (bForce == TRUE)
    2095               0 :         PreParseFile();
    2096                 : 
    2097               0 :     if (m_bPreParsed)
    2098                 :     {
    2099               0 :         *psExtent = m_sExtents;
    2100               0 :         return OGRERR_NONE;
    2101                 :     }
    2102                 :     else
    2103               0 :         return OGRERR_FAILURE;
    2104                 : }
    2105                 : 
    2106                 : /************************************************************************/
    2107                 : /*                           TestCapability()                           */
    2108                 : /************************************************************************/
    2109                 : 
    2110               0 : int MIFFile::TestCapability( const char * pszCap )
    2111                 : 
    2112                 : {
    2113               0 :     if( EQUAL(pszCap,OLCRandomRead) )
    2114               0 :         return TRUE;
    2115                 : 
    2116               0 :     else if( EQUAL(pszCap,OLCSequentialWrite) )
    2117               0 :         return TRUE;
    2118                 : 
    2119               0 :     else if( EQUAL(pszCap,OLCSequentialWrite) )
    2120               0 :         return FALSE;
    2121                 : 
    2122               0 :     else if( EQUAL(pszCap,OLCFastFeatureCount) )
    2123               0 :         return m_bPreParsed;
    2124                 : 
    2125               0 :     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
    2126               0 :         return FALSE;
    2127                 : 
    2128               0 :     else if( EQUAL(pszCap,OLCFastGetExtent) )
    2129               0 :         return m_bPreParsed;
    2130                 : 
    2131                 :     else 
    2132               0 :         return FALSE;
    2133                 : }

Generated by: LCOV version 1.7