LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_miffile.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 805 377 46.8 %
Date: 2012-12-26 Functions: 34 16 47.1 %

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

Generated by: LCOV version 1.7